...

Source file src/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go

Documentation: sigs.k8s.io/kustomize/kyaml/yaml

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package yaml
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"log"
    10  	"os"
    11  	"regexp"
    12  	"strconv"
    13  	"strings"
    14  
    15  	"sigs.k8s.io/kustomize/kyaml/errors"
    16  	"sigs.k8s.io/kustomize/kyaml/sliceutil"
    17  	"sigs.k8s.io/kustomize/kyaml/utils"
    18  	"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels"
    19  	yaml "sigs.k8s.io/yaml/goyaml.v3"
    20  )
    21  
    22  // MakeNullNode returns an RNode that represents an empty document.
    23  func MakeNullNode() *RNode {
    24  	return NewRNode(&Node{Tag: NodeTagNull})
    25  }
    26  
    27  // MakePersistentNullNode returns an RNode that should be persisted,
    28  // even when merging
    29  func MakePersistentNullNode(value string) *RNode {
    30  	n := NewRNode(
    31  		&Node{
    32  			Tag:   NodeTagNull,
    33  			Value: value,
    34  			Kind:  yaml.ScalarNode,
    35  		},
    36  	)
    37  	n.ShouldKeep = true
    38  	return n
    39  }
    40  
    41  // IsMissingOrNull is true if the RNode is nil or explicitly tagged null.
    42  // TODO: make this a method on RNode.
    43  func IsMissingOrNull(node *RNode) bool {
    44  	return node.IsNil() || node.YNode().Tag == NodeTagNull
    45  }
    46  
    47  // IsEmptyMap returns true if the RNode is an empty node or an empty map.
    48  // TODO: make this a method on RNode.
    49  func IsEmptyMap(node *RNode) bool {
    50  	return IsMissingOrNull(node) || IsYNodeEmptyMap(node.YNode())
    51  }
    52  
    53  // GetValue returns underlying yaml.Node Value field
    54  func GetValue(node *RNode) string {
    55  	if IsMissingOrNull(node) {
    56  		return ""
    57  	}
    58  	return node.YNode().Value
    59  }
    60  
    61  // Parse parses a yaml string into an *RNode.
    62  // To parse multiple resources, consider a kio.ByteReader
    63  func Parse(value string) (*RNode, error) {
    64  	return Parser{Value: value}.Filter(nil)
    65  }
    66  
    67  // ReadFile parses a single Resource from a yaml file.
    68  // To parse multiple resources, consider a kio.ByteReader
    69  func ReadFile(path string) (*RNode, error) {
    70  	b, err := os.ReadFile(path)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	return Parse(string(b))
    75  }
    76  
    77  // WriteFile writes a single Resource to a yaml file
    78  func WriteFile(node *RNode, path string) error {
    79  	out, err := node.String()
    80  	if err != nil {
    81  		return err
    82  	}
    83  	return errors.WrapPrefixf(os.WriteFile(path, []byte(out), 0600), "writing RNode to file")
    84  }
    85  
    86  // UpdateFile reads the file at path, applies the filter to it, and write the result back.
    87  // path must contain a exactly 1 resource (YAML).
    88  func UpdateFile(filter Filter, path string) error {
    89  	// Read the yaml
    90  	y, err := ReadFile(path)
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	// Update the yaml
    96  	if err := y.PipeE(filter); err != nil {
    97  		return err
    98  	}
    99  
   100  	// Write the yaml
   101  	return WriteFile(y, path)
   102  }
   103  
   104  // MustParse parses a yaml string into an *RNode and panics if there is an error
   105  func MustParse(value string) *RNode {
   106  	v, err := Parser{Value: value}.Filter(nil)
   107  	if err != nil {
   108  		panic(err)
   109  	}
   110  	return v
   111  }
   112  
   113  // NewScalarRNode returns a new Scalar *RNode containing the provided scalar value.
   114  func NewScalarRNode(value string) *RNode {
   115  	return &RNode{
   116  		value: &yaml.Node{
   117  			Kind:  yaml.ScalarNode,
   118  			Value: value,
   119  		}}
   120  }
   121  
   122  // NewStringRNode returns a new Scalar *RNode containing the provided string.
   123  // If the string is non-utf8, it will be base64 encoded, and the tag
   124  // will indicate binary data.
   125  func NewStringRNode(value string) *RNode {
   126  	n := yaml.Node{Kind: yaml.ScalarNode}
   127  	n.SetString(value)
   128  	return NewRNode(&n)
   129  }
   130  
   131  // NewListRNode returns a new List *RNode containing the provided scalar values.
   132  func NewListRNode(values ...string) *RNode {
   133  	seq := &RNode{value: &yaml.Node{Kind: yaml.SequenceNode}}
   134  	for _, v := range values {
   135  		seq.value.Content = append(seq.value.Content, &yaml.Node{
   136  			Kind:  yaml.ScalarNode,
   137  			Value: v,
   138  		})
   139  	}
   140  	return seq
   141  }
   142  
   143  // NewMapRNode returns a new Map *RNode containing the provided values
   144  func NewMapRNode(values *map[string]string) *RNode {
   145  	m := &RNode{value: &yaml.Node{
   146  		Kind: yaml.MappingNode,
   147  	}}
   148  	if values == nil {
   149  		return m
   150  	}
   151  
   152  	for k, v := range *values {
   153  		m.value.Content = append(m.value.Content, &yaml.Node{
   154  			Kind:  yaml.ScalarNode,
   155  			Value: k,
   156  		}, &yaml.Node{
   157  			Kind:  yaml.ScalarNode,
   158  			Value: v,
   159  		})
   160  	}
   161  
   162  	return m
   163  }
   164  
   165  // SyncMapNodesOrder sorts the map node keys in 'to' node to match the order of
   166  // map node keys in 'from' node, additional keys are moved to the end
   167  func SyncMapNodesOrder(from, to *RNode) {
   168  	to.Copy()
   169  	res := &RNode{value: &yaml.Node{
   170  		Kind:        to.YNode().Kind,
   171  		Style:       to.YNode().Style,
   172  		Tag:         to.YNode().Tag,
   173  		Anchor:      to.YNode().Anchor,
   174  		Alias:       to.YNode().Alias,
   175  		HeadComment: to.YNode().HeadComment,
   176  		LineComment: to.YNode().LineComment,
   177  		FootComment: to.YNode().FootComment,
   178  		Line:        to.YNode().Line,
   179  		Column:      to.YNode().Column,
   180  	}}
   181  
   182  	fromFieldNames, err := from.Fields()
   183  	if err != nil {
   184  		return
   185  	}
   186  
   187  	toFieldNames, err := to.Fields()
   188  	if err != nil {
   189  		return
   190  	}
   191  
   192  	for _, fieldName := range fromFieldNames {
   193  		if !sliceutil.Contains(toFieldNames, fieldName) {
   194  			continue
   195  		}
   196  		// append the common nodes in the order defined in 'from' node
   197  		res.value.Content = append(res.value.Content, to.Field(fieldName).Key.YNode(), to.Field(fieldName).Value.YNode())
   198  		toFieldNames = sliceutil.Remove(toFieldNames, fieldName)
   199  	}
   200  
   201  	for _, fieldName := range toFieldNames {
   202  		// append the residual nodes which are not present in 'from' node
   203  		res.value.Content = append(res.value.Content, to.Field(fieldName).Key.YNode(), to.Field(fieldName).Value.YNode())
   204  	}
   205  
   206  	to.SetYNode(res.YNode())
   207  }
   208  
   209  // NewRNode returns a new RNode pointer containing the provided Node.
   210  func NewRNode(value *yaml.Node) *RNode {
   211  	return &RNode{value: value}
   212  }
   213  
   214  // RNode provides functions for manipulating Kubernetes Resources
   215  // Objects unmarshalled into *yaml.Nodes
   216  type RNode struct {
   217  	// fieldPath contains the path from the root of the KubernetesObject to
   218  	// this field.
   219  	// Only field names are captured in the path.
   220  	// e.g. a image field in a Deployment would be
   221  	// 'spec.template.spec.containers.image'
   222  	fieldPath []string
   223  
   224  	// FieldValue contains the value.
   225  	// FieldValue is always set:
   226  	// field: field value
   227  	// list entry: list entry value
   228  	// object root: object root
   229  	value *yaml.Node
   230  
   231  	// Whether we should keep this node, even if otherwise we would clear it
   232  	ShouldKeep bool
   233  
   234  	Match []string
   235  }
   236  
   237  // Copy returns a distinct copy.
   238  func (rn *RNode) Copy() *RNode {
   239  	if rn == nil {
   240  		return nil
   241  	}
   242  	result := *rn
   243  	result.value = CopyYNode(rn.value)
   244  	return &result
   245  }
   246  
   247  var ErrMissingMetadata = fmt.Errorf("missing Resource metadata")
   248  
   249  // IsNil is true if the node is nil, or its underlying YNode is nil.
   250  func (rn *RNode) IsNil() bool {
   251  	return rn == nil || rn.YNode() == nil
   252  }
   253  
   254  // IsTaggedNull is true if a non-nil node is explicitly tagged Null.
   255  func (rn *RNode) IsTaggedNull() bool {
   256  	return !rn.IsNil() && IsYNodeTaggedNull(rn.YNode())
   257  }
   258  
   259  // IsNilOrEmpty is true if the node is nil,
   260  // has no YNode, or has YNode that appears empty.
   261  func (rn *RNode) IsNilOrEmpty() bool {
   262  	return rn.IsNil() || IsYNodeNilOrEmpty(rn.YNode())
   263  }
   264  
   265  // IsStringValue is true if the RNode is not nil and is scalar string node
   266  func (rn *RNode) IsStringValue() bool {
   267  	return !rn.IsNil() && IsYNodeString(rn.YNode())
   268  }
   269  
   270  // GetMeta returns the ResourceMeta for an RNode
   271  func (rn *RNode) GetMeta() (ResourceMeta, error) {
   272  	if IsMissingOrNull(rn) {
   273  		return ResourceMeta{}, nil
   274  	}
   275  	missingMeta := true
   276  	n := rn
   277  	if n.YNode().Kind == DocumentNode {
   278  		// get the content is this is the document node
   279  		n = NewRNode(n.Content()[0])
   280  	}
   281  
   282  	// don't decode into the struct directly or it will fail on UTF-8 issues
   283  	// which appear in comments
   284  	m := ResourceMeta{}
   285  
   286  	// TODO: consider optimizing this parsing
   287  	if f := n.Field(APIVersionField); !f.IsNilOrEmpty() {
   288  		m.APIVersion = GetValue(f.Value)
   289  		missingMeta = false
   290  	}
   291  	if f := n.Field(KindField); !f.IsNilOrEmpty() {
   292  		m.Kind = GetValue(f.Value)
   293  		missingMeta = false
   294  	}
   295  
   296  	mf := n.Field(MetadataField)
   297  	if mf.IsNilOrEmpty() {
   298  		if missingMeta {
   299  			return m, ErrMissingMetadata
   300  		}
   301  		return m, nil
   302  	}
   303  	meta := mf.Value
   304  
   305  	if f := meta.Field(NameField); !f.IsNilOrEmpty() {
   306  		m.Name = f.Value.YNode().Value
   307  		missingMeta = false
   308  	}
   309  	if f := meta.Field(NamespaceField); !f.IsNilOrEmpty() {
   310  		m.Namespace = GetValue(f.Value)
   311  		missingMeta = false
   312  	}
   313  
   314  	if f := meta.Field(LabelsField); !f.IsNilOrEmpty() {
   315  		m.Labels = map[string]string{}
   316  		_ = f.Value.VisitFields(func(node *MapNode) error {
   317  			m.Labels[GetValue(node.Key)] = GetValue(node.Value)
   318  			return nil
   319  		})
   320  		missingMeta = false
   321  	}
   322  	if f := meta.Field(AnnotationsField); !f.IsNilOrEmpty() {
   323  		m.Annotations = map[string]string{}
   324  		_ = f.Value.VisitFields(func(node *MapNode) error {
   325  			m.Annotations[GetValue(node.Key)] = GetValue(node.Value)
   326  			return nil
   327  		})
   328  		missingMeta = false
   329  	}
   330  
   331  	if missingMeta {
   332  		return m, ErrMissingMetadata
   333  	}
   334  	return m, nil
   335  }
   336  
   337  // Pipe sequentially invokes each Filter, and passes the result to the next
   338  // Filter.
   339  //
   340  // Analogous to http://www.linfo.org/pipes.html
   341  //
   342  // * rn is provided as input to the first Filter.
   343  // * if any Filter returns an error, immediately return the error
   344  // * if any Filter returns a nil RNode, immediately return nil, nil
   345  // * if all Filters succeed with non-empty results, return the final result
   346  func (rn *RNode) Pipe(functions ...Filter) (*RNode, error) {
   347  	// check if rn is nil to make chaining Pipe calls easier
   348  	if rn == nil {
   349  		return nil, nil
   350  	}
   351  
   352  	var v *RNode
   353  	var err error
   354  	if rn.value != nil && rn.value.Kind == yaml.DocumentNode {
   355  		// the first node may be a DocumentNode containing a single MappingNode
   356  		v = &RNode{value: rn.value.Content[0]}
   357  	} else {
   358  		v = rn
   359  	}
   360  
   361  	// return each fn in sequence until encountering an error or missing value
   362  	for _, c := range functions {
   363  		v, err = c.Filter(v)
   364  		if err != nil || v == nil {
   365  			return v, errors.Wrap(err)
   366  		}
   367  	}
   368  	return v, err
   369  }
   370  
   371  // PipeE runs Pipe, dropping the *RNode return value.
   372  // Useful for directly returning the Pipe error value from functions.
   373  func (rn *RNode) PipeE(functions ...Filter) error {
   374  	_, err := rn.Pipe(functions...)
   375  	return errors.Wrap(err)
   376  }
   377  
   378  // Document returns the Node for the value.
   379  func (rn *RNode) Document() *yaml.Node {
   380  	return rn.value
   381  }
   382  
   383  // YNode returns the yaml.Node value.  If the yaml.Node value is a DocumentNode,
   384  // YNode will return the DocumentNode Content entry instead of the DocumentNode.
   385  func (rn *RNode) YNode() *yaml.Node {
   386  	if rn == nil || rn.value == nil {
   387  		return nil
   388  	}
   389  	if rn.value.Kind == yaml.DocumentNode {
   390  		return rn.value.Content[0]
   391  	}
   392  	return rn.value
   393  }
   394  
   395  // SetYNode sets the yaml.Node value on an RNode.
   396  func (rn *RNode) SetYNode(node *yaml.Node) {
   397  	if rn.value == nil || node == nil {
   398  		rn.value = node
   399  		return
   400  	}
   401  	*rn.value = *node
   402  }
   403  
   404  // GetKind returns the kind, if it exists, else empty string.
   405  func (rn *RNode) GetKind() string {
   406  	if node := rn.getMapFieldValue(KindField); node != nil {
   407  		return node.Value
   408  	}
   409  	return ""
   410  }
   411  
   412  // SetKind sets the kind.
   413  func (rn *RNode) SetKind(k string) {
   414  	rn.SetMapField(NewScalarRNode(k), KindField)
   415  }
   416  
   417  // GetApiVersion returns the apiversion, if it exists, else empty string.
   418  func (rn *RNode) GetApiVersion() string {
   419  	if node := rn.getMapFieldValue(APIVersionField); node != nil {
   420  		return node.Value
   421  	}
   422  	return ""
   423  }
   424  
   425  // SetApiVersion sets the apiVersion.
   426  func (rn *RNode) SetApiVersion(av string) {
   427  	rn.SetMapField(NewScalarRNode(av), APIVersionField)
   428  }
   429  
   430  // getMapFieldValue returns the value (*yaml.Node) of a mapping field.
   431  // The value might be nil.  Also, the function returns nil, not an error,
   432  // if this node is not a mapping node, or if this node does not have the
   433  // given field, so this function cannot be used to make distinctions
   434  // between these cases.
   435  func (rn *RNode) getMapFieldValue(field string) *yaml.Node {
   436  	var result *yaml.Node
   437  	visitMappingNodeFields(rn.Content(), func(key, value *yaml.Node) {
   438  		result = value
   439  	}, field)
   440  	return result
   441  }
   442  
   443  // GetName returns the name, or empty string if
   444  // field not found.  The setter is more restrictive.
   445  func (rn *RNode) GetName() string {
   446  	return rn.getMetaStringField(NameField)
   447  }
   448  
   449  // getMetaStringField returns the value of a string field in metadata.
   450  func (rn *RNode) getMetaStringField(fName string) string {
   451  	md := rn.getMetaData()
   452  	if md == nil {
   453  		return ""
   454  	}
   455  	var result string
   456  	visitMappingNodeFields(md.Content, func(key, value *yaml.Node) {
   457  		if !IsYNodeNilOrEmpty(value) {
   458  			result = value.Value
   459  		}
   460  	}, fName)
   461  	return result
   462  }
   463  
   464  // getMetaData returns the *yaml.Node of the metadata field.
   465  // Return nil if field not found (no error).
   466  func (rn *RNode) getMetaData() *yaml.Node {
   467  	if IsMissingOrNull(rn) {
   468  		return nil
   469  	}
   470  	content := rn.Content()
   471  	if rn.YNode().Kind == DocumentNode {
   472  		// get the content if this is the document node
   473  		content = content[0].Content
   474  	}
   475  	var mf *yaml.Node
   476  	visitMappingNodeFields(content, func(key, value *yaml.Node) {
   477  		if !IsYNodeNilOrEmpty(value) {
   478  			mf = value
   479  		}
   480  	}, MetadataField)
   481  	return mf
   482  }
   483  
   484  // SetName sets the metadata name field.
   485  func (rn *RNode) SetName(name string) error {
   486  	return rn.SetMapField(NewScalarRNode(name), MetadataField, NameField)
   487  }
   488  
   489  // GetNamespace gets the metadata namespace field, or empty string if
   490  // field not found.  The setter is more restrictive.
   491  func (rn *RNode) GetNamespace() string {
   492  	return rn.getMetaStringField(NamespaceField)
   493  }
   494  
   495  // SetNamespace tries to set the metadata namespace field.  If the argument
   496  // is empty, the field is dropped.
   497  func (rn *RNode) SetNamespace(ns string) error {
   498  	meta, err := rn.Pipe(Lookup(MetadataField))
   499  	if err != nil {
   500  		return err
   501  	}
   502  	if ns == "" {
   503  		if rn == nil {
   504  			return nil
   505  		}
   506  		return meta.PipeE(Clear(NamespaceField))
   507  	}
   508  	return rn.SetMapField(
   509  		NewScalarRNode(ns), MetadataField, NamespaceField)
   510  }
   511  
   512  // GetAnnotations gets the metadata annotations field.
   513  // If the annotations field is missing, returns an empty map.
   514  // Use another method to check for missing metadata.
   515  // If specific annotations are provided, then the map is
   516  // restricted to only those entries with keys that match
   517  // one of the specific annotations. If no annotations are
   518  // provided, then the map will contain all entries.
   519  func (rn *RNode) GetAnnotations(annotations ...string) map[string]string {
   520  	return rn.getMapFromMeta(AnnotationsField, annotations...)
   521  }
   522  
   523  // SetAnnotations tries to set the metadata annotations field.
   524  func (rn *RNode) SetAnnotations(m map[string]string) error {
   525  	return rn.setMapInMetadata(m, AnnotationsField)
   526  }
   527  
   528  // GetLabels gets the metadata labels field.
   529  // If the labels field is missing, returns an empty map.
   530  // Use another method to check for missing metadata.
   531  // If specific labels are provided, then the map is
   532  // restricted to only those entries with keys that match
   533  // one of the specific labels. If no labels are
   534  // provided, then the map will contain all entries.
   535  func (rn *RNode) GetLabels(labels ...string) map[string]string {
   536  	return rn.getMapFromMeta(LabelsField, labels...)
   537  }
   538  
   539  // getMapFromMeta returns a map, sometimes empty, from the fName
   540  // field in the node's metadata field.
   541  // If specific fields are provided, then the map is
   542  // restricted to only those entries with keys that match
   543  // one of the specific fields. If no fields are
   544  // provided, then the map will contain all entries.
   545  func (rn *RNode) getMapFromMeta(fName string, fields ...string) map[string]string {
   546  	meta := rn.getMetaData()
   547  	if meta == nil {
   548  		return make(map[string]string)
   549  	}
   550  
   551  	var result map[string]string
   552  
   553  	visitMappingNodeFields(meta.Content, func(_, fNameValue *yaml.Node) {
   554  		// fName is found in metadata; create the map from its content
   555  		expectedSize := len(fields)
   556  		if expectedSize == 0 {
   557  			expectedSize = len(fNameValue.Content) / 2 //nolint: gomnd
   558  		}
   559  		result = make(map[string]string, expectedSize)
   560  
   561  		visitMappingNodeFields(fNameValue.Content, func(key, value *yaml.Node) {
   562  			result[key.Value] = value.Value
   563  		}, fields...)
   564  	}, fName)
   565  
   566  	if result == nil {
   567  		return make(map[string]string)
   568  	}
   569  	return result
   570  }
   571  
   572  // SetLabels sets the metadata labels field.
   573  func (rn *RNode) SetLabels(m map[string]string) error {
   574  	return rn.setMapInMetadata(m, LabelsField)
   575  }
   576  
   577  // This established proper quoting on string values, and sorts by key.
   578  func (rn *RNode) setMapInMetadata(m map[string]string, field string) error {
   579  	meta, err := rn.Pipe(LookupCreate(MappingNode, MetadataField))
   580  	if err != nil {
   581  		return err
   582  	}
   583  	if err = meta.PipeE(Clear(field)); err != nil {
   584  		return err
   585  	}
   586  	if len(m) == 0 {
   587  		return nil
   588  	}
   589  	mapNode, err := meta.Pipe(LookupCreate(MappingNode, field))
   590  	if err != nil {
   591  		return err
   592  	}
   593  	for _, k := range SortedMapKeys(m) {
   594  		if _, err := mapNode.Pipe(
   595  			SetField(k, NewStringRNode(m[k]))); err != nil {
   596  			return err
   597  		}
   598  	}
   599  	return nil
   600  }
   601  
   602  func (rn *RNode) SetMapField(value *RNode, path ...string) error {
   603  	return rn.PipeE(
   604  		LookupCreate(yaml.MappingNode, path[0:len(path)-1]...),
   605  		SetField(path[len(path)-1], value),
   606  	)
   607  }
   608  
   609  func (rn *RNode) GetDataMap() map[string]string {
   610  	n, err := rn.Pipe(Lookup(DataField))
   611  	if err != nil {
   612  		return nil
   613  	}
   614  	result := map[string]string{}
   615  	_ = n.VisitFields(func(node *MapNode) error {
   616  		result[GetValue(node.Key)] = GetValue(node.Value)
   617  		return nil
   618  	})
   619  	return result
   620  }
   621  
   622  func (rn *RNode) GetBinaryDataMap() map[string]string {
   623  	n, err := rn.Pipe(Lookup(BinaryDataField))
   624  	if err != nil {
   625  		return nil
   626  	}
   627  	result := map[string]string{}
   628  	_ = n.VisitFields(func(node *MapNode) error {
   629  		result[GetValue(node.Key)] = GetValue(node.Value)
   630  		return nil
   631  	})
   632  	return result
   633  }
   634  
   635  // GetValidatedDataMap retrieves the data map and returns an error if the data
   636  // map contains entries which are not included in the expectedKeys set.
   637  func (rn *RNode) GetValidatedDataMap(expectedKeys []string) (map[string]string, error) {
   638  	dataMap := rn.GetDataMap()
   639  	err := rn.validateDataMap(dataMap, expectedKeys)
   640  	return dataMap, err
   641  }
   642  
   643  func (rn *RNode) validateDataMap(dataMap map[string]string, expectedKeys []string) error {
   644  	if dataMap == nil {
   645  		return fmt.Errorf("The datamap is unassigned")
   646  	}
   647  	for key := range dataMap {
   648  		found := false
   649  		for _, expected := range expectedKeys {
   650  			if expected == key {
   651  				found = true
   652  			}
   653  		}
   654  		if !found {
   655  			return fmt.Errorf("an unexpected key (%v) was found", key)
   656  		}
   657  	}
   658  	return nil
   659  }
   660  
   661  func (rn *RNode) SetDataMap(m map[string]string) {
   662  	if rn == nil {
   663  		log.Fatal("cannot set data map on nil Rnode")
   664  	}
   665  	if err := rn.PipeE(Clear(DataField)); err != nil {
   666  		log.Fatal(err)
   667  	}
   668  	if len(m) == 0 {
   669  		return
   670  	}
   671  	if err := rn.LoadMapIntoConfigMapData(m); err != nil {
   672  		log.Fatal(err)
   673  	}
   674  }
   675  
   676  func (rn *RNode) SetBinaryDataMap(m map[string]string) {
   677  	if rn == nil {
   678  		log.Fatal("cannot set binaryData map on nil Rnode")
   679  	}
   680  	if err := rn.PipeE(Clear(BinaryDataField)); err != nil {
   681  		log.Fatal(err)
   682  	}
   683  	if len(m) == 0 {
   684  		return
   685  	}
   686  	if err := rn.LoadMapIntoConfigMapBinaryData(m); err != nil {
   687  		log.Fatal(err)
   688  	}
   689  }
   690  
   691  // AppendToFieldPath appends a field name to the FieldPath.
   692  func (rn *RNode) AppendToFieldPath(parts ...string) {
   693  	rn.fieldPath = append(rn.fieldPath, parts...)
   694  }
   695  
   696  // FieldPath returns the field path from the Resource root node, to rn.
   697  // Does not include list indexes.
   698  func (rn *RNode) FieldPath() []string {
   699  	return rn.fieldPath
   700  }
   701  
   702  // String returns string representation of the RNode
   703  func (rn *RNode) String() (string, error) {
   704  	if rn == nil {
   705  		return "", nil
   706  	}
   707  	return String(rn.value)
   708  }
   709  
   710  // MustString returns string representation of the RNode or panics if there is an error
   711  func (rn *RNode) MustString() string {
   712  	s, err := rn.String()
   713  	if err != nil {
   714  		panic(err)
   715  	}
   716  	return s
   717  }
   718  
   719  // Content returns Node Content field.
   720  func (rn *RNode) Content() []*yaml.Node {
   721  	if rn == nil {
   722  		return nil
   723  	}
   724  	return rn.YNode().Content
   725  }
   726  
   727  // Fields returns the list of field names for a MappingNode.
   728  // Returns an error for non-MappingNodes.
   729  func (rn *RNode) Fields() ([]string, error) {
   730  	if err := ErrorIfInvalid(rn, yaml.MappingNode); err != nil {
   731  		return nil, errors.Wrap(err)
   732  	}
   733  	var fields []string
   734  	visitMappingNodeFields(rn.Content(), func(key, value *yaml.Node) {
   735  		fields = append(fields, key.Value)
   736  	})
   737  	return fields, nil
   738  }
   739  
   740  // FieldRNodes returns the list of field key RNodes for a MappingNode.
   741  // Returns an error for non-MappingNodes.
   742  func (rn *RNode) FieldRNodes() ([]*RNode, error) {
   743  	if err := ErrorIfInvalid(rn, yaml.MappingNode); err != nil {
   744  		return nil, errors.Wrap(err)
   745  	}
   746  	var fields []*RNode
   747  	visitMappingNodeFields(rn.Content(), func(key, value *yaml.Node) {
   748  		// for each key node in the input mapping node contents create equivalent rNode
   749  		rNode := &RNode{}
   750  		rNode.SetYNode(key)
   751  		fields = append(fields, rNode)
   752  	})
   753  	return fields, nil
   754  }
   755  
   756  // Field returns a fieldName, fieldValue pair for MappingNodes.
   757  // Returns nil for non-MappingNodes.
   758  func (rn *RNode) Field(field string) *MapNode {
   759  	if rn.YNode().Kind != yaml.MappingNode {
   760  		return nil
   761  	}
   762  	var result *MapNode
   763  	visitMappingNodeFields(rn.Content(), func(key, value *yaml.Node) {
   764  		result = &MapNode{Key: NewRNode(key), Value: NewRNode(value)}
   765  	}, field)
   766  	return result
   767  }
   768  
   769  // VisitFields calls fn for each field in the RNode.
   770  // Returns an error for non-MappingNodes.
   771  func (rn *RNode) VisitFields(fn func(node *MapNode) error) error {
   772  	// get the list of srcFieldNames
   773  	srcFieldNames, err := rn.Fields()
   774  	if err != nil {
   775  		return errors.Wrap(err)
   776  	}
   777  
   778  	// visit each field
   779  	for _, fieldName := range srcFieldNames {
   780  		if err := fn(rn.Field(fieldName)); err != nil {
   781  			return errors.Wrap(err)
   782  		}
   783  	}
   784  	return nil
   785  }
   786  
   787  // visitMappingNodeFields calls fn for fields in the content, in content order.
   788  // The caller is responsible to ensure the node is a mapping node. If fieldNames
   789  // are specified, then fn is called only for the fields that match the given
   790  // fieldNames.
   791  func visitMappingNodeFields(content []*yaml.Node, fn func(key, value *yaml.Node), fieldNames ...string) {
   792  	switch len(fieldNames) {
   793  	case 0: // visit all fields
   794  		visitFieldsWhileTrue(content, func(key, value *yaml.Node, _ int) bool {
   795  			fn(key, value)
   796  			return true
   797  		})
   798  	case 1: // visit single field
   799  		visitFieldsWhileTrue(content, func(key, value *yaml.Node, _ int) bool {
   800  			if key == nil {
   801  				return true
   802  			}
   803  			if fieldNames[0] == key.Value {
   804  				fn(key, value)
   805  				return false
   806  			}
   807  			return true
   808  		})
   809  	default: // visit specified fields
   810  		fieldsStillToVisit := make(map[string]bool, len(fieldNames))
   811  		for _, fieldName := range fieldNames {
   812  			fieldsStillToVisit[fieldName] = true
   813  		}
   814  		visitFieldsWhileTrue(content, func(key, value *yaml.Node, _ int) bool {
   815  			if key == nil {
   816  				return true
   817  			}
   818  			if fieldsStillToVisit[key.Value] {
   819  				fn(key, value)
   820  				delete(fieldsStillToVisit, key.Value)
   821  			}
   822  			return len(fieldsStillToVisit) > 0
   823  		})
   824  	}
   825  }
   826  
   827  // visitFieldsWhileTrue calls fn for the fields in content, in content order,
   828  // until either fn returns false or all fields have been visited. The caller
   829  // should ensure that content is from a mapping node, or fits the same expected
   830  // pattern (consecutive key/value entries in the slice).
   831  func visitFieldsWhileTrue(content []*yaml.Node, fn func(key, value *yaml.Node, keyIndex int) bool) {
   832  	for i := 0; i < len(content); i += 2 {
   833  		continueVisiting := fn(content[i], content[i+1], i)
   834  		if !continueVisiting {
   835  			return
   836  		}
   837  	}
   838  }
   839  
   840  // Elements returns the list of elements in the RNode.
   841  // Returns an error for non-SequenceNodes.
   842  func (rn *RNode) Elements() ([]*RNode, error) {
   843  	if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
   844  		return nil, errors.Wrap(err)
   845  	}
   846  	var elements []*RNode
   847  	for i := 0; i < len(rn.Content()); i++ {
   848  		elements = append(elements, NewRNode(rn.Content()[i]))
   849  	}
   850  	return elements, nil
   851  }
   852  
   853  // ElementValues returns a list of all observed values for a given field name
   854  // in a list of elements.
   855  // Returns error for non-SequenceNodes.
   856  func (rn *RNode) ElementValues(key string) ([]string, error) {
   857  	if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
   858  		return nil, errors.Wrap(err)
   859  	}
   860  	var elements []string
   861  	for i := 0; i < len(rn.Content()); i++ {
   862  		field := NewRNode(rn.Content()[i]).Field(key)
   863  		if !field.IsNilOrEmpty() {
   864  			elements = append(elements, field.Value.YNode().Value)
   865  		}
   866  	}
   867  	return elements, nil
   868  }
   869  
   870  // ElementValuesList returns a list of lists, where each list is a set of
   871  // values corresponding to each key in keys.
   872  // Returns error for non-SequenceNodes.
   873  func (rn *RNode) ElementValuesList(keys []string) ([][]string, error) {
   874  	if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
   875  		return nil, errors.Wrap(err)
   876  	}
   877  	elements := make([][]string, len(rn.Content()))
   878  
   879  	for i := 0; i < len(rn.Content()); i++ {
   880  		for _, key := range keys {
   881  			field := NewRNode(rn.Content()[i]).Field(key)
   882  			if field.IsNilOrEmpty() {
   883  				elements[i] = append(elements[i], "")
   884  			} else {
   885  				elements[i] = append(elements[i], field.Value.YNode().Value)
   886  			}
   887  		}
   888  	}
   889  	return elements, nil
   890  }
   891  
   892  // Element returns the element in the list which contains the field matching the value.
   893  // Returns nil for non-SequenceNodes or if no Element matches.
   894  func (rn *RNode) Element(key, value string) *RNode {
   895  	if rn.YNode().Kind != yaml.SequenceNode {
   896  		return nil
   897  	}
   898  	elem, err := rn.Pipe(MatchElement(key, value))
   899  	if err != nil {
   900  		return nil
   901  	}
   902  	return elem
   903  }
   904  
   905  // ElementList returns the element in the list in which all fields keys[i] matches all
   906  // corresponding values[i].
   907  // Returns nil for non-SequenceNodes or if no Element matches.
   908  func (rn *RNode) ElementList(keys []string, values []string) *RNode {
   909  	if rn.YNode().Kind != yaml.SequenceNode {
   910  		return nil
   911  	}
   912  	elem, err := rn.Pipe(MatchElementList(keys, values))
   913  	if err != nil {
   914  		return nil
   915  	}
   916  	return elem
   917  }
   918  
   919  // VisitElements calls fn for each element in a SequenceNode.
   920  // Returns an error for non-SequenceNodes
   921  func (rn *RNode) VisitElements(fn func(node *RNode) error) error {
   922  	elements, err := rn.Elements()
   923  	if err != nil {
   924  		return errors.Wrap(err)
   925  	}
   926  
   927  	for i := range elements {
   928  		if err := fn(elements[i]); err != nil {
   929  			return errors.Wrap(err)
   930  		}
   931  	}
   932  	return nil
   933  }
   934  
   935  // AssociativeSequenceKeys is a map of paths to sequences that have associative keys.
   936  // The order sets the precedence of the merge keys -- if multiple keys are present
   937  // in Resources in a list, then the FIRST key which ALL elements in the list have is used as the
   938  // associative key for merging that list.
   939  // Only infer name as a merge key.
   940  var AssociativeSequenceKeys = []string{"name"}
   941  
   942  // IsAssociative returns true if the RNode contains an AssociativeSequenceKey as a field.
   943  func (rn *RNode) IsAssociative() bool {
   944  	return rn.GetAssociativeKey() != ""
   945  }
   946  
   947  // GetAssociativeKey returns the AssociativeSequenceKey used to merge the elements in the
   948  // SequenceNode, or "" if the  list is not associative.
   949  func (rn *RNode) GetAssociativeKey() string {
   950  	// look for any associative keys in the first element
   951  	for _, key := range AssociativeSequenceKeys {
   952  		if checkKey(key, rn.Content()) {
   953  			return key
   954  		}
   955  	}
   956  
   957  	// element doesn't have an associative keys
   958  	return ""
   959  }
   960  
   961  // MarshalJSON creates a byte slice from the RNode.
   962  func (rn *RNode) MarshalJSON() ([]byte, error) {
   963  	s, err := rn.String()
   964  	if err != nil {
   965  		return nil, err
   966  	}
   967  
   968  	if rn.YNode().Kind == SequenceNode {
   969  		var a []interface{}
   970  		if err := Unmarshal([]byte(s), &a); err != nil {
   971  			return nil, err
   972  		}
   973  		return json.Marshal(a)
   974  	}
   975  
   976  	m := map[string]interface{}{}
   977  	if err := Unmarshal([]byte(s), &m); err != nil {
   978  		return nil, err
   979  	}
   980  	return json.Marshal(m)
   981  }
   982  
   983  // UnmarshalJSON overwrites this RNode with data from []byte.
   984  func (rn *RNode) UnmarshalJSON(b []byte) error {
   985  	m := map[string]interface{}{}
   986  	if err := json.Unmarshal(b, &m); err != nil {
   987  		return err
   988  	}
   989  	r, err := FromMap(m)
   990  	if err != nil {
   991  		return err
   992  	}
   993  	rn.value = r.value
   994  	return nil
   995  }
   996  
   997  // DeAnchor inflates all YAML aliases with their anchor values.
   998  // All YAML anchor data is permanently removed (feel free to call Copy first).
   999  func (rn *RNode) DeAnchor() (err error) {
  1000  	rn.value, err = deAnchor(rn.value)
  1001  	return
  1002  }
  1003  
  1004  // deAnchor removes all AliasNodes from the yaml.Node's tree, replacing
  1005  // them with what they point to.  All Anchor fields (these are used to mark
  1006  // anchor definitions) are cleared.
  1007  func deAnchor(yn *yaml.Node) (res *yaml.Node, err error) {
  1008  	if yn == nil {
  1009  		return nil, nil
  1010  	}
  1011  	if yn.Anchor != "" {
  1012  		// This node defines an anchor. Clear the field so that it
  1013  		// doesn't show up when marshalling.
  1014  		if yn.Kind == yaml.AliasNode {
  1015  			// Maybe this is OK, but for now treating it as a bug.
  1016  			return nil, fmt.Errorf(
  1017  				"anchor %q defined using alias %v", yn.Anchor, yn.Alias)
  1018  		}
  1019  		yn.Anchor = ""
  1020  	}
  1021  	switch yn.Kind {
  1022  	case yaml.ScalarNode:
  1023  		return yn, nil
  1024  	case yaml.AliasNode:
  1025  		result, err := deAnchor(yn.Alias)
  1026  		if err != nil {
  1027  			return nil, err
  1028  		}
  1029  		return CopyYNode(result), nil
  1030  	case yaml.MappingNode:
  1031  		toMerge, err := removeMergeTags(yn)
  1032  		if err != nil {
  1033  			return nil, err
  1034  		}
  1035  		err = mergeAll(yn, toMerge)
  1036  		if err != nil {
  1037  			return nil, err
  1038  		}
  1039  		fallthrough
  1040  	case yaml.DocumentNode, yaml.SequenceNode:
  1041  		for i := range yn.Content {
  1042  			yn.Content[i], err = deAnchor(yn.Content[i])
  1043  			if err != nil {
  1044  				return nil, err
  1045  			}
  1046  		}
  1047  		return yn, nil
  1048  	default:
  1049  		return nil, fmt.Errorf("cannot deAnchor kind %q", yn.Kind)
  1050  	}
  1051  }
  1052  
  1053  // isMerge returns if the node is tagged with !!merge
  1054  func isMerge(yn *yaml.Node) bool {
  1055  	return yn.Tag == MergeTag
  1056  }
  1057  
  1058  // findMergeValues receives either a MappingNode, a AliasNode or a potentially
  1059  // mixed list of MappingNodes and AliasNodes. It returns a list of MappingNodes.
  1060  func findMergeValues(yn *yaml.Node) ([]*yaml.Node, error) {
  1061  	if yn == nil {
  1062  		return []*yaml.Node{}, nil
  1063  	}
  1064  	switch yn.Kind {
  1065  	case MappingNode:
  1066  		return []*yaml.Node{yn}, nil
  1067  	case AliasNode:
  1068  		if yn.Alias != nil && yn.Alias.Kind != MappingNode {
  1069  			return nil, errors.Errorf("invalid map merge: received alias for a non-map value")
  1070  		}
  1071  		return []*yaml.Node{yn.Alias}, nil
  1072  	case SequenceNode:
  1073  		mergeValues := []*yaml.Node{}
  1074  		for i := 0; i < len(yn.Content); i++ {
  1075  			if yn.Content[i].Kind == SequenceNode {
  1076  				return nil, errors.Errorf("invalid map merge: received a nested sequence")
  1077  			}
  1078  			newMergeValues, err := findMergeValues(yn.Content[i])
  1079  			if err != nil {
  1080  				return nil, err
  1081  			}
  1082  			mergeValues = append(newMergeValues, mergeValues...)
  1083  		}
  1084  		return mergeValues, nil
  1085  	default:
  1086  		return nil, errors.Errorf("map merge requires map or sequence of maps as the value")
  1087  	}
  1088  }
  1089  
  1090  // getMergeTagValue receives a MappingNode yaml node, and it searches for
  1091  // merge tagged keys and return its value yaml node. If the key is duplicated,
  1092  // it fails.
  1093  func getMergeTagValue(yn *yaml.Node) (*yaml.Node, error) {
  1094  	var result *yaml.Node
  1095  	var err error
  1096  	visitFieldsWhileTrue(yn.Content, func(key, value *yaml.Node, _ int) bool {
  1097  		if isMerge(key) {
  1098  			if result != nil {
  1099  				err = fmt.Errorf("duplicate merge key")
  1100  				result = nil
  1101  				return false
  1102  			}
  1103  			result = value
  1104  		}
  1105  		return true
  1106  	})
  1107  	return result, err
  1108  }
  1109  
  1110  // removeMergeTags removes all merge tags and returns a ordered list of yaml
  1111  // nodes to merge and a error
  1112  func removeMergeTags(yn *yaml.Node) ([]*yaml.Node, error) {
  1113  	if yn == nil || yn.Content == nil {
  1114  		return nil, nil
  1115  	}
  1116  	if yn.Kind != yaml.MappingNode {
  1117  		return nil, nil
  1118  	}
  1119  	value, err := getMergeTagValue(yn)
  1120  	if err != nil {
  1121  		return nil, err
  1122  	}
  1123  	toMerge, err := findMergeValues(value)
  1124  	if err != nil {
  1125  		return nil, err
  1126  	}
  1127  	err = NewRNode(yn).PipeE(Clear("<<"))
  1128  	if err != nil {
  1129  		return nil, err
  1130  	}
  1131  	return toMerge, nil
  1132  }
  1133  
  1134  func mergeAll(yn *yaml.Node, toMerge []*yaml.Node) error {
  1135  	// We only need to start with a copy of the existing node because we need to
  1136  	// maintain duplicated keys and style
  1137  	rn := NewRNode(yn).Copy()
  1138  	toMerge = append(toMerge, yn)
  1139  	for i := range toMerge {
  1140  		rnToMerge := NewRNode(toMerge[i]).Copy()
  1141  		err := rnToMerge.VisitFields(func(node *MapNode) error {
  1142  			return rn.PipeE(MapEntrySetter{Key: node.Key, Value: node.Value})
  1143  		})
  1144  		if err != nil {
  1145  			return err
  1146  		}
  1147  	}
  1148  	*yn = *rn.value
  1149  	return nil
  1150  }
  1151  
  1152  // GetValidatedMetadata returns metadata after subjecting it to some tests.
  1153  func (rn *RNode) GetValidatedMetadata() (ResourceMeta, error) {
  1154  	m, err := rn.GetMeta()
  1155  	if err != nil {
  1156  		return m, err
  1157  	}
  1158  	if m.Kind == "" {
  1159  		return m, fmt.Errorf("missing kind in object %v", m)
  1160  	}
  1161  	if strings.HasSuffix(m.Kind, "List") {
  1162  		// A list doesn't require a name.
  1163  		return m, nil
  1164  	}
  1165  	if m.NameMeta.Name == "" {
  1166  		return m, fmt.Errorf("missing metadata.name in object %v", m)
  1167  	}
  1168  	return m, nil
  1169  }
  1170  
  1171  // MatchesAnnotationSelector returns true on a selector match to annotations.
  1172  func (rn *RNode) MatchesAnnotationSelector(selector string) (bool, error) {
  1173  	s, err := labels.Parse(selector)
  1174  	if err != nil {
  1175  		return false, err
  1176  	}
  1177  	return s.Matches(labels.Set(rn.GetAnnotations())), nil
  1178  }
  1179  
  1180  // MatchesLabelSelector returns true on a selector match to labels.
  1181  func (rn *RNode) MatchesLabelSelector(selector string) (bool, error) {
  1182  	s, err := labels.Parse(selector)
  1183  	if err != nil {
  1184  		return false, err
  1185  	}
  1186  	return s.Matches(labels.Set(rn.GetLabels())), nil
  1187  }
  1188  
  1189  // HasNilEntryInList returns true if the RNode contains a list which has
  1190  // a nil item, along with the path to the missing item.
  1191  // TODO(broken): This doesn't do what it claims to do.
  1192  // (see TODO in unit test and pr 1513).
  1193  func (rn *RNode) HasNilEntryInList() (bool, string) {
  1194  	return hasNilEntryInList(rn.value)
  1195  }
  1196  
  1197  func hasNilEntryInList(in interface{}) (bool, string) {
  1198  	switch v := in.(type) {
  1199  	case map[string]interface{}:
  1200  		for key, s := range v {
  1201  			if result, path := hasNilEntryInList(s); result {
  1202  				return result, key + "/" + path
  1203  			}
  1204  		}
  1205  	case []interface{}:
  1206  		for index, s := range v {
  1207  			if s == nil {
  1208  				return true, ""
  1209  			}
  1210  			if result, path := hasNilEntryInList(s); result {
  1211  				return result, "[" + strconv.Itoa(index) + "]/" + path
  1212  			}
  1213  		}
  1214  	}
  1215  	return false, ""
  1216  }
  1217  
  1218  func FromMap(m map[string]interface{}) (*RNode, error) {
  1219  	c, err := Marshal(m)
  1220  	if err != nil {
  1221  		return nil, err
  1222  	}
  1223  	return Parse(string(c))
  1224  }
  1225  
  1226  func (rn *RNode) Map() (map[string]interface{}, error) {
  1227  	if rn == nil || rn.value == nil {
  1228  		return make(map[string]interface{}), nil
  1229  	}
  1230  	var result map[string]interface{}
  1231  	if err := rn.value.Decode(&result); err != nil {
  1232  		// Should not be able to create an RNode that cannot be decoded;
  1233  		// this is an unrecoverable error.
  1234  		str, _ := rn.String()
  1235  		return nil, fmt.Errorf("received error %w for the following resource:\n%s", err, str)
  1236  	}
  1237  	return result, nil
  1238  }
  1239  
  1240  // ConvertJSONToYamlNode parses input json string and returns equivalent yaml node
  1241  func ConvertJSONToYamlNode(jsonStr string) (*RNode, error) {
  1242  	var body map[string]interface{}
  1243  	err := json.Unmarshal([]byte(jsonStr), &body)
  1244  	if err != nil {
  1245  		return nil, err
  1246  	}
  1247  	yml, err := yaml.Marshal(body)
  1248  	if err != nil {
  1249  		return nil, err
  1250  	}
  1251  	node, err := Parse(string(yml))
  1252  	if err != nil {
  1253  		return nil, err
  1254  	}
  1255  	return node, nil
  1256  }
  1257  
  1258  // checkKey returns true if all elems have the key
  1259  func checkKey(key string, elems []*Node) bool {
  1260  	count := 0
  1261  	for i := range elems {
  1262  		elem := NewRNode(elems[i])
  1263  		if elem.Field(key) != nil {
  1264  			count++
  1265  		}
  1266  	}
  1267  	return count == len(elems)
  1268  }
  1269  
  1270  // GetSlice returns the contents of the slice field at the given path.
  1271  func (rn *RNode) GetSlice(path string) ([]interface{}, error) {
  1272  	value, err := rn.GetFieldValue(path)
  1273  	if err != nil {
  1274  		return nil, err
  1275  	}
  1276  	if sliceValue, ok := value.([]interface{}); ok {
  1277  		return sliceValue, nil
  1278  	}
  1279  	return nil, fmt.Errorf("node %s is not a slice", path)
  1280  }
  1281  
  1282  // GetString returns the contents of the string field at the given path.
  1283  func (rn *RNode) GetString(path string) (string, error) {
  1284  	value, err := rn.GetFieldValue(path)
  1285  	if err != nil {
  1286  		return "", err
  1287  	}
  1288  	if v, ok := value.(string); ok {
  1289  		return v, nil
  1290  	}
  1291  	return "", fmt.Errorf("node %s is not a string: %v", path, value)
  1292  }
  1293  
  1294  // GetFieldValue finds period delimited fields.
  1295  // TODO: When doing kustomize var replacement, which is likely a
  1296  // a primary use of this function and the reason it returns interface{}
  1297  // rather than string, we do conversion from Nodes to Go types and back
  1298  // to nodes.  We should figure out how to do replacement using raw nodes,
  1299  // assuming we keep the var feature in kustomize.
  1300  // The other end of this is: refvar.go:updateNodeValue.
  1301  func (rn *RNode) GetFieldValue(path string) (interface{}, error) {
  1302  	fields := convertSliceIndex(utils.SmarterPathSplitter(path, "."))
  1303  	rn, err := rn.Pipe(Lookup(fields...))
  1304  	if err != nil {
  1305  		return nil, err
  1306  	}
  1307  	if rn == nil {
  1308  		return nil, NoFieldError{path}
  1309  	}
  1310  	yn := rn.YNode()
  1311  
  1312  	// If this is an alias node, resolve it
  1313  	if yn.Kind == yaml.AliasNode {
  1314  		yn = yn.Alias
  1315  	}
  1316  
  1317  	// Return value as map for DocumentNode and MappingNode kinds
  1318  	if yn.Kind == yaml.DocumentNode || yn.Kind == yaml.MappingNode {
  1319  		var result map[string]interface{}
  1320  		if err := yn.Decode(&result); err != nil {
  1321  			return nil, err
  1322  		}
  1323  		return result, err
  1324  	}
  1325  
  1326  	// Return value as slice for SequenceNode kind
  1327  	if yn.Kind == yaml.SequenceNode {
  1328  		var result []interface{}
  1329  		if err := yn.Decode(&result); err != nil {
  1330  			return nil, err
  1331  		}
  1332  		return result, nil
  1333  	}
  1334  	if yn.Kind != yaml.ScalarNode {
  1335  		return nil, fmt.Errorf("expected ScalarNode, got Kind=%d", yn.Kind)
  1336  	}
  1337  
  1338  	switch yn.Tag {
  1339  	case NodeTagString:
  1340  		return yn.Value, nil
  1341  	case NodeTagInt:
  1342  		return strconv.Atoi(yn.Value)
  1343  	case NodeTagFloat:
  1344  		return strconv.ParseFloat(yn.Value, 64)
  1345  	case NodeTagBool:
  1346  		return strconv.ParseBool(yn.Value)
  1347  	default:
  1348  		// Possibly this should be an error or log.
  1349  		return yn.Value, nil
  1350  	}
  1351  }
  1352  
  1353  // convertSliceIndex traverses the items in `fields` and find
  1354  // if there is a slice index in the item and change it to a
  1355  // valid Lookup field path. For example, 'ports[0]' will be
  1356  // converted to 'ports' and '0'.
  1357  func convertSliceIndex(fields []string) []string {
  1358  	var res []string
  1359  	for _, s := range fields {
  1360  		if !strings.HasSuffix(s, "]") {
  1361  			res = append(res, s)
  1362  			continue
  1363  		}
  1364  		re := regexp.MustCompile(`^(.*)\[(\d+)\]$`)
  1365  		groups := re.FindStringSubmatch(s)
  1366  		if len(groups) == 0 {
  1367  			// no match, add to result
  1368  			res = append(res, s)
  1369  			continue
  1370  		}
  1371  		if groups[1] != "" {
  1372  			res = append(res, groups[1])
  1373  		}
  1374  		res = append(res, groups[2])
  1375  	}
  1376  	return res
  1377  }
  1378  
  1379  type NoFieldError struct {
  1380  	Field string
  1381  }
  1382  
  1383  func (e NoFieldError) Error() string {
  1384  	return fmt.Sprintf("no field named '%s'", e.Field)
  1385  }
  1386  

View as plain text