k8s.io/apiserver@v0.31.1/pkg/util/flowcontrol/format/formatting.go (about)

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package format
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"fmt"
    23  
    24  	flowcontrol "k8s.io/api/flowcontrol/v1"
    25  	"k8s.io/apiserver/pkg/authentication/user"
    26  	"k8s.io/apiserver/pkg/endpoints/request"
    27  )
    28  
    29  // This file provides an easy way to mark a value for formatting to
    30  // `%s` in full detail IF it is printed but without costing a lot of
    31  // CPU or memory if the value is NOT printed.  The API Priority and
    32  // Fairness API objects are formatted into JSON.  The other types of
    33  // objects here are formatted into golang source.
    34  
    35  // Stringer marks the given value for custom formatting by this package.
    36  type Stringer struct{ val interface{} }
    37  
    38  // Fmt marks the given value for custom formatting by this package.
    39  func Fmt(val interface{}) Stringer {
    40  	return Stringer{val}
    41  }
    42  
    43  // String formats to a string in full detail
    44  func (sr Stringer) String() string {
    45  	if sr.val == nil {
    46  		return "nil"
    47  	}
    48  	switch typed := sr.val.(type) {
    49  	case *flowcontrol.FlowSchema,
    50  		flowcontrol.FlowSchema,
    51  		flowcontrol.FlowSchemaSpec,
    52  		flowcontrol.FlowDistinguisherMethod,
    53  		*flowcontrol.FlowDistinguisherMethod,
    54  		*flowcontrol.PolicyRulesWithSubjects,
    55  		flowcontrol.PolicyRulesWithSubjects,
    56  		flowcontrol.Subject,
    57  		flowcontrol.ResourcePolicyRule,
    58  		flowcontrol.NonResourcePolicyRule,
    59  		flowcontrol.FlowSchemaCondition,
    60  		*flowcontrol.PriorityLevelConfiguration,
    61  		flowcontrol.PriorityLevelConfiguration,
    62  		flowcontrol.PriorityLevelConfigurationSpec,
    63  		*flowcontrol.LimitedPriorityLevelConfiguration,
    64  		flowcontrol.LimitedPriorityLevelConfiguration,
    65  		flowcontrol.LimitResponse,
    66  		*flowcontrol.QueuingConfiguration,
    67  		flowcontrol.QueuingConfiguration:
    68  		return ToJSON(sr.val)
    69  	case []user.Info:
    70  		return FmtUsers(typed)
    71  	case []*request.RequestInfo:
    72  		return FmtRequests(typed)
    73  	default:
    74  		return fmt.Sprintf("%#+v", sr.val)
    75  	}
    76  }
    77  
    78  // ToJSON converts using encoding/json and handles errors by
    79  // formatting them
    80  func ToJSON(val interface{}) string {
    81  	bs, err := json.Marshal(val)
    82  	str := string(bs)
    83  	if err != nil {
    84  		str = str + "<" + err.Error() + ">"
    85  	}
    86  	return str
    87  }
    88  
    89  // FmtPriorityLevelConfiguration returns a golang source expression
    90  // equivalent to the given value
    91  func FmtPriorityLevelConfiguration(pl *flowcontrol.PriorityLevelConfiguration) string {
    92  	if pl == nil {
    93  		return "nil"
    94  	}
    95  	var buf bytes.Buffer
    96  	buf.WriteString(fmt.Sprintf("&flowcontrolv1.PriorityLevelConfiguration{ObjectMeta: %#+v, Spec: ",
    97  		pl.ObjectMeta))
    98  	BufferPriorityLevelConfigurationSpec(&buf, &pl.Spec)
    99  	buf.WriteString(fmt.Sprintf(", Status: %#+v}", pl.Status))
   100  	return buf.String()
   101  }
   102  
   103  // FmtPriorityLevelConfigurationSpec returns a golang source
   104  // expression equivalent to the given value
   105  func FmtPriorityLevelConfigurationSpec(plSpec *flowcontrol.PriorityLevelConfigurationSpec) string {
   106  	var buf bytes.Buffer
   107  	BufferPriorityLevelConfigurationSpec(&buf, plSpec)
   108  	return buf.String()
   109  }
   110  
   111  // BufferPriorityLevelConfigurationSpec writes a golang source
   112  // expression for the given value to the given buffer
   113  func BufferPriorityLevelConfigurationSpec(buf *bytes.Buffer, plSpec *flowcontrol.PriorityLevelConfigurationSpec) {
   114  	buf.WriteString(fmt.Sprintf("flowcontrolv1.PriorityLevelConfigurationSpec{Type: %#v", plSpec.Type))
   115  	if plSpec.Limited != nil {
   116  		buf.WriteString(fmt.Sprintf(", Limited: &flowcontrol.LimitedPriorityLevelConfiguration{NominalConcurrencyShares:%d, LimitResponse:flowcontrol.LimitResponse{Type:%#v", plSpec.Limited.NominalConcurrencyShares, plSpec.Limited.LimitResponse.Type))
   117  		if plSpec.Limited.LimitResponse.Queuing != nil {
   118  			buf.WriteString(fmt.Sprintf(", Queuing:&%#+v", *plSpec.Limited.LimitResponse.Queuing))
   119  		}
   120  		buf.WriteString(" } }")
   121  	}
   122  	buf.WriteString("}")
   123  }
   124  
   125  // FmtFlowSchema produces a golang source expression of the value.
   126  func FmtFlowSchema(fs *flowcontrol.FlowSchema) string {
   127  	if fs == nil {
   128  		return "nil"
   129  	}
   130  	var buf bytes.Buffer
   131  	buf.WriteString(fmt.Sprintf("&flowcontrolv1.FlowSchema{ObjectMeta: %#+v, Spec: ",
   132  		fs.ObjectMeta))
   133  	BufferFlowSchemaSpec(&buf, &fs.Spec)
   134  	buf.WriteString(fmt.Sprintf(", Status: %#+v}", fs.Status))
   135  	return buf.String()
   136  }
   137  
   138  // FmtFlowSchemaSpec produces a golang source expression equivalent to
   139  // the given spec
   140  func FmtFlowSchemaSpec(fsSpec *flowcontrol.FlowSchemaSpec) string {
   141  	var buf bytes.Buffer
   142  	BufferFlowSchemaSpec(&buf, fsSpec)
   143  	return buf.String()
   144  }
   145  
   146  // BufferFlowSchemaSpec writes a golang source expression for the
   147  // given value to the given buffer
   148  func BufferFlowSchemaSpec(buf *bytes.Buffer, fsSpec *flowcontrol.FlowSchemaSpec) {
   149  	buf.WriteString(fmt.Sprintf("flowcontrolv1.FlowSchemaSpec{PriorityLevelConfiguration: %#+v, MatchingPrecedence: %d, DistinguisherMethod: ",
   150  		fsSpec.PriorityLevelConfiguration,
   151  		fsSpec.MatchingPrecedence))
   152  	if fsSpec.DistinguisherMethod == nil {
   153  		buf.WriteString("nil")
   154  	} else {
   155  		buf.WriteString(fmt.Sprintf("&%#+v", *fsSpec.DistinguisherMethod))
   156  	}
   157  	buf.WriteString(", Rules: []flowcontrol.PolicyRulesWithSubjects{")
   158  	for idx, rule := range fsSpec.Rules {
   159  		if idx > 0 {
   160  			buf.WriteString(", ")
   161  		}
   162  		BufferFmtPolicyRulesWithSubjectsSlim(buf, rule)
   163  	}
   164  	buf.WriteString("}}")
   165  }
   166  
   167  // FmtPolicyRulesWithSubjects produces a golang source expression of the value.
   168  func FmtPolicyRulesWithSubjects(rule flowcontrol.PolicyRulesWithSubjects) string {
   169  	return "flowcontrolv1.PolicyRulesWithSubjects" + FmtPolicyRulesWithSubjectsSlim(rule)
   170  }
   171  
   172  // FmtPolicyRulesWithSubjectsSlim produces a golang source expression
   173  // of the value but without the leading type name.  See above for an
   174  // example context where this is useful.
   175  func FmtPolicyRulesWithSubjectsSlim(rule flowcontrol.PolicyRulesWithSubjects) string {
   176  	var buf bytes.Buffer
   177  	BufferFmtPolicyRulesWithSubjectsSlim(&buf, rule)
   178  	return buf.String()
   179  }
   180  
   181  // BufferFmtPolicyRulesWithSubjectsSlim writes a golang source
   182  // expression for the given value to the given buffer but excludes the
   183  // leading type name
   184  func BufferFmtPolicyRulesWithSubjectsSlim(buf *bytes.Buffer, rule flowcontrol.PolicyRulesWithSubjects) {
   185  	buf.WriteString("{Subjects: []flowcontrolv1.Subject{")
   186  	for jdx, subj := range rule.Subjects {
   187  		if jdx > 0 {
   188  			buf.WriteString(", ")
   189  		}
   190  		buf.WriteString(fmt.Sprintf("{Kind: %q", subj.Kind))
   191  		if subj.User != nil {
   192  			buf.WriteString(fmt.Sprintf(", User: &%#+v", *subj.User))
   193  		}
   194  		if subj.Group != nil {
   195  			buf.WriteString(fmt.Sprintf(", Group: &%#+v", *subj.Group))
   196  		}
   197  		if subj.ServiceAccount != nil {
   198  			buf.WriteString(fmt.Sprintf(", ServiceAccount: &%#+v", *subj.ServiceAccount))
   199  		}
   200  		buf.WriteString("}")
   201  	}
   202  	buf.WriteString(fmt.Sprintf("}, ResourceRules: %#+v, NonResourceRules: %#+v}", rule.ResourceRules, rule.NonResourceRules))
   203  }
   204  
   205  // FmtUsers produces a golang source expression of the value.
   206  func FmtUsers(list []user.Info) string {
   207  	var buf bytes.Buffer
   208  	buf.WriteString("[]user.Info{")
   209  	for idx, member := range list {
   210  		if idx > 0 {
   211  			buf.WriteString(", ")
   212  		}
   213  		buf.WriteString(fmt.Sprintf("%#+v", member))
   214  	}
   215  	buf.WriteString("}")
   216  	return buf.String()
   217  }
   218  
   219  // FmtRequests produces a golang source expression of the value.
   220  func FmtRequests(list []*request.RequestInfo) string {
   221  	var buf bytes.Buffer
   222  	buf.WriteString("[]*request.RequestInfo{")
   223  	for idx, member := range list {
   224  		if idx > 0 {
   225  			buf.WriteString(", ")
   226  		}
   227  		buf.WriteString(fmt.Sprintf("%#+v", member))
   228  	}
   229  	buf.WriteString("}")
   230  	return buf.String()
   231  }