...

Source file src/k8s.io/kubernetes/pkg/fieldpath/fieldpath.go

Documentation: k8s.io/kubernetes/pkg/fieldpath

     1  /*
     2  Copyright 2015 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 fieldpath
    18  
    19  import (
    20  	"fmt"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  
    25  	"k8s.io/apimachinery/pkg/api/meta"
    26  	"k8s.io/apimachinery/pkg/util/validation"
    27  )
    28  
    29  // FormatMap formats map[string]string to a string.
    30  func FormatMap(m map[string]string) (fmtStr string) {
    31  	// output with keys in sorted order to provide stable output
    32  	keys := make([]string, 0, len(m))
    33  	var grow int
    34  	for k, v := range m {
    35  		keys = append(keys, k)
    36  		// why add 4: (for =, \n, " and ")
    37  		grow += len(k) + len(v) + 4
    38  	}
    39  	sort.Strings(keys)
    40  	// allocate space to avoid expansion
    41  	dst := make([]byte, 0, grow)
    42  	for _, key := range keys {
    43  		if len(dst) > 0 {
    44  			dst = append(dst, '\n')
    45  		}
    46  		dst = append(dst, key...)
    47  		dst = append(dst, '=')
    48  		dst = strconv.AppendQuote(dst, m[key])
    49  	}
    50  	return string(dst)
    51  }
    52  
    53  // ExtractFieldPathAsString extracts the field from the given object
    54  // and returns it as a string.  The object must be a pointer to an
    55  // API type.
    56  func ExtractFieldPathAsString(obj interface{}, fieldPath string) (string, error) {
    57  	accessor, err := meta.Accessor(obj)
    58  	if err != nil {
    59  		return "", err
    60  	}
    61  
    62  	if path, subscript, ok := SplitMaybeSubscriptedPath(fieldPath); ok {
    63  		switch path {
    64  		case "metadata.annotations":
    65  			if errs := validation.IsQualifiedName(strings.ToLower(subscript)); len(errs) != 0 {
    66  				return "", fmt.Errorf("invalid key subscript in %s: %s", fieldPath, strings.Join(errs, ";"))
    67  			}
    68  			return accessor.GetAnnotations()[subscript], nil
    69  		case "metadata.labels":
    70  			if errs := validation.IsQualifiedName(subscript); len(errs) != 0 {
    71  				return "", fmt.Errorf("invalid key subscript in %s: %s", fieldPath, strings.Join(errs, ";"))
    72  			}
    73  			return accessor.GetLabels()[subscript], nil
    74  		default:
    75  			return "", fmt.Errorf("fieldPath %q does not support subscript", fieldPath)
    76  		}
    77  	}
    78  
    79  	switch fieldPath {
    80  	case "metadata.annotations":
    81  		return FormatMap(accessor.GetAnnotations()), nil
    82  	case "metadata.labels":
    83  		return FormatMap(accessor.GetLabels()), nil
    84  	case "metadata.name":
    85  		return accessor.GetName(), nil
    86  	case "metadata.namespace":
    87  		return accessor.GetNamespace(), nil
    88  	case "metadata.uid":
    89  		return string(accessor.GetUID()), nil
    90  	}
    91  
    92  	return "", fmt.Errorf("unsupported fieldPath: %v", fieldPath)
    93  }
    94  
    95  // SplitMaybeSubscriptedPath checks whether the specified fieldPath is
    96  // subscripted, and
    97  //   - if yes, this function splits the fieldPath into path and subscript, and
    98  //     returns (path, subscript, true).
    99  //   - if no, this function returns (fieldPath, "", false).
   100  //
   101  // Example inputs and outputs:
   102  //
   103  //	"metadata.annotations['myKey']" --> ("metadata.annotations", "myKey", true)
   104  //	"metadata.annotations['a[b]c']" --> ("metadata.annotations", "a[b]c", true)
   105  //	"metadata.labels['']"           --> ("metadata.labels", "", true)
   106  //	"metadata.labels"               --> ("metadata.labels", "", false)
   107  func SplitMaybeSubscriptedPath(fieldPath string) (string, string, bool) {
   108  	if !strings.HasSuffix(fieldPath, "']") {
   109  		return fieldPath, "", false
   110  	}
   111  	s := strings.TrimSuffix(fieldPath, "']")
   112  	parts := strings.SplitN(s, "['", 2)
   113  	if len(parts) < 2 {
   114  		return fieldPath, "", false
   115  	}
   116  	if len(parts[0]) == 0 {
   117  		return fieldPath, "", false
   118  	}
   119  	return parts[0], parts[1], true
   120  }
   121  

View as plain text