mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Update documentation for kyaml package
This commit is contained in:
20
kyaml/doc.go
Normal file
20
kyaml/doc.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package kyaml contains libraries for reading and writing Kubernetes Resource configuration
|
||||
// as yaml.
|
||||
//
|
||||
// Resources
|
||||
//
|
||||
// Individual Resources are manipulated using the yaml package.
|
||||
// import (
|
||||
// "sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
// )
|
||||
//
|
||||
// Collections of Resources
|
||||
//
|
||||
// Collections of Resources are manipulated using the kio package.
|
||||
// import (
|
||||
// "sigs.k8s.io/kustomize/kyaml/kio"
|
||||
// )
|
||||
package kyaml
|
||||
@@ -19,7 +19,7 @@ const (
|
||||
ResourceListApiVersion = "kyaml.kustomize.dev/v1alpha1"
|
||||
)
|
||||
|
||||
// ByteReadWriter reads from an input and writes to an output
|
||||
// ByteReadWriter reads from an input and writes to an output.
|
||||
type ByteReadWriter struct {
|
||||
// Reader is where ResourceNodes are decoded from.
|
||||
Reader io.Reader
|
||||
|
||||
32
kyaml/kio/doc.go
Normal file
32
kyaml/kio/doc.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Package kio contains libraries for reading and writing collections of Resources.
|
||||
//
|
||||
// Reading Resources
|
||||
//
|
||||
// Resources are Read using a kio.Reader function. Examples:
|
||||
// [kio.LocalPackageReader{}, kio.ByteReader{}]
|
||||
//
|
||||
// Resources read using a LocalPackageReader will have annotations applied so they can be
|
||||
// written back to the files they were read from.
|
||||
//
|
||||
// Modifying Resources
|
||||
//
|
||||
// Resources are modified using a kio.Filter. The kio.Filter accepts a collection of
|
||||
// Resources as input, and returns a new collection as output.
|
||||
// It is recommended to use the yaml package for manipulating individual Resources in
|
||||
// the collection.
|
||||
//
|
||||
// Writing Resources
|
||||
//
|
||||
// Resources are Read using a kio.Reader function. Examples:
|
||||
// [kio.LocalPackageWriter{}, kio.ByteWriter{}]
|
||||
//
|
||||
// ReadWriters
|
||||
//
|
||||
// It is preferred to use a ReadWriter when reading and writing from / to the same source.
|
||||
//
|
||||
// Building Pipelines
|
||||
//
|
||||
// The preferred way to transforms a collection of Resources is to use kio.Pipeline to Read,
|
||||
// Modify and Write the collection of Resources. Pipeline will automatically sequentially
|
||||
// invoke the Read, Modify, Write steps, returning and error immediately on any failure.
|
||||
package kio
|
||||
@@ -30,22 +30,23 @@ type Writer interface {
|
||||
Write([]*yaml.RNode) error
|
||||
}
|
||||
|
||||
// WriterFunc implements a Writer as a function.
|
||||
type WriterFunc func([]*yaml.RNode) error
|
||||
|
||||
func (fn WriterFunc) Write(o []*yaml.RNode) error {
|
||||
return fn(o)
|
||||
}
|
||||
|
||||
// GrepFilter modifies a collection of Resource Configuration by returning the modified slice.
|
||||
// Filter modifies a collection of Resource Configuration by returning the modified slice.
|
||||
// When possible, Filters should be serializable to yaml so that they can be described
|
||||
// declaratively as data.
|
||||
// as either data or code.
|
||||
//
|
||||
// Analogous to http://www.linfo.org/filters.html
|
||||
type Filter interface {
|
||||
Filter([]*yaml.RNode) ([]*yaml.RNode, error)
|
||||
}
|
||||
|
||||
// FilterFunc can be used to implement GrepFilter by defining a function.
|
||||
// FilterFunc implements a Filter as a function.
|
||||
type FilterFunc func([]*yaml.RNode) ([]*yaml.RNode, error)
|
||||
|
||||
func (fn FilterFunc) Filter(o []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
@@ -53,7 +54,7 @@ func (fn FilterFunc) Filter(o []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
}
|
||||
|
||||
// Pipeline reads Resource Configuration from a set of Inputs, applies some
|
||||
// transformations, and writes the results to a set of Outputs.
|
||||
// transformation filters, and writes the results to a set of Outputs.
|
||||
//
|
||||
// Analogous to http://www.linfo.org/pipes.html
|
||||
type Pipeline struct {
|
||||
@@ -69,7 +70,8 @@ type Pipeline struct {
|
||||
Outputs []Writer `yaml:"outputs,omitempty"`
|
||||
}
|
||||
|
||||
// Execute implements the Pipeline pipeline.
|
||||
// Execute executes each step in the sequence, returning immediately after encountering
|
||||
// any error as part of the Pipeline.
|
||||
func (p Pipeline) Execute() error {
|
||||
var result []*yaml.RNode
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
// files.
|
||||
var requiredResourcePackageAnnotations = []string{kioutil.IndexAnnotation, kioutil.PathAnnotation}
|
||||
|
||||
// PackageBuffer implements Reader and Writer, storing Resources in a local field.
|
||||
type PackageBuffer struct {
|
||||
Nodes []*yaml.RNode
|
||||
}
|
||||
@@ -30,6 +31,9 @@ func (r *PackageBuffer) Write(nodes []*yaml.RNode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalPackageReadWriter reads and writes Resources from / to a local directory.
|
||||
// When writing, LocalPackageReadWriter will delete files if all of the Resources from
|
||||
// that file have been removed from the output.
|
||||
type LocalPackageReadWriter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ const (
|
||||
TreeStructureGraph TreeStructure = "graph"
|
||||
)
|
||||
|
||||
// TreeWriter prints the package structured as a tree
|
||||
// TreeWriter prints the package structured as a tree.
|
||||
// TODO(pwittrock): test this package better. it is lower-risk since it is only
|
||||
// used for printing rather than updating or editing.
|
||||
type TreeWriter struct {
|
||||
|
||||
@@ -1,12 +1,49 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package yaml contains low-level libraries for manipulating individual Kubernetes Resource
|
||||
// Configuration yaml.
|
||||
// Package yaml contains libraries for manipulating individual Kubernetes Resource
|
||||
// Configuration as yaml, keeping yaml structure and comments.
|
||||
//
|
||||
// It exports the public pieces of "gopkg.in/yaml.v3", so can be used as a drop in replacement.
|
||||
// Parsing Resources
|
||||
//
|
||||
// This package should be used over sigs.k8s.io/yaml:
|
||||
// - If retaining or modifying yaml comments, structure, formatting
|
||||
// - If Resources should be round tripped without dropping fields
|
||||
// Typically Resources will be initialized as collections through the kio package libraries.
|
||||
// However it is possible to directly initialize Resources using Parse.
|
||||
// resource, err := yaml.Parse("apiVersion: apps/v1\nkind: Deployment")
|
||||
//
|
||||
// Processing Resources
|
||||
//
|
||||
// Individual Resources are manipulated using the Pipe and PipeE to apply Filter functions
|
||||
// to transform the Resource data.
|
||||
// err := resource.PipeE(yaml.SetAnnotation("key", "value"))
|
||||
//
|
||||
// If multiple Filter functions are provided to Pipe or PipeE, each function is applied to
|
||||
// the result of the last function -- e.g. yaml.Lookup(...), yaml.SetField(...)
|
||||
//
|
||||
// Field values may also be retrieved using Pipe.
|
||||
// annotationValue, err := resource.Pipe(yaml.GetAnnotation("key"))
|
||||
//
|
||||
// See http://www.linfo.org/filters.html for a definition of filters.
|
||||
//
|
||||
// Common Filters
|
||||
//
|
||||
// There are a number of standard filter functions provided by the yaml package.
|
||||
//
|
||||
// Working with annotations:
|
||||
// [AnnotationSetter{}, AnnotationGetter{}, AnnotationClearer{}]
|
||||
//
|
||||
// Working with fields by path:
|
||||
// [PathMatcher{}, PathGetter{}]
|
||||
//
|
||||
// Working with individual fields on Maps and Objects:
|
||||
// [FieldMatcher{}, FieldSetter{}, FieldGetter{}]
|
||||
//
|
||||
// Working with individual elements in Sequences:
|
||||
// [ElementAppender{}, ElementSetter{}, ElementMatcher{}]
|
||||
//
|
||||
// Writing Filters
|
||||
//
|
||||
// Users may implement their own filter functions. When doing so, can be necessary to work with
|
||||
// the RNode directly rather than through Pipe. RNode provides a number of functions for doing
|
||||
// so. See:
|
||||
// [GetMeta(), Fields(), Elements(), String()]
|
||||
package yaml
|
||||
|
||||
@@ -839,3 +839,56 @@ spec:
|
||||
// - bar
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleRNode_Elements() {
|
||||
resource, err := Parse(`
|
||||
- name: foo
|
||||
args: ['run.sh']
|
||||
- name: bar
|
||||
args: ['run.sh']
|
||||
- name: baz
|
||||
args: ['run.sh']
|
||||
`)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
elements, err := resource.Elements()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for i, e := range elements {
|
||||
fmt.Println(fmt.Sprintf("Element: %d", i))
|
||||
fmt.Println(e.MustString())
|
||||
}
|
||||
// Output:
|
||||
// Element: 0
|
||||
// name: foo
|
||||
// args: ['run.sh']
|
||||
//
|
||||
// Element: 1
|
||||
// name: bar
|
||||
// args: ['run.sh']
|
||||
//
|
||||
// Element: 2
|
||||
// name: baz
|
||||
// args: ['run.sh']
|
||||
|
||||
}
|
||||
|
||||
func ExampleRNode_ElementValues() {
|
||||
resource, err := Parse(`
|
||||
- name: foo
|
||||
args: ['run.sh']
|
||||
- name: bar
|
||||
args: ['run.sh']
|
||||
- name: baz
|
||||
args: ['run.sh']
|
||||
`)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(resource.ElementValues("name"))
|
||||
// Output:
|
||||
// [foo bar baz] <nil>
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Filters is the list of serializable Pipeline Filters
|
||||
var Filters = map[string]func() Filter{
|
||||
"AnnotationClearer": func() Filter { return &AnnotationClearer{} },
|
||||
"AnnotationGetter": func() Filter { return &AnnotationGetter{} },
|
||||
@@ -29,7 +30,9 @@ var Filters = map[string]func() Filter{
|
||||
"TeePiper": func() Filter { return &TeePiper{} },
|
||||
}
|
||||
|
||||
// YFilter wraps the GrepFilter interface so it can be unmarshalled into a struct.
|
||||
// YFilter wraps the GrepFilter interface so the filter can be represented as
|
||||
// data and can be unmarshalled into a struct from a yaml config file.
|
||||
// This allows Pipelines to be expressed as data rather than code.
|
||||
type YFilter struct {
|
||||
Filter
|
||||
}
|
||||
|
||||
@@ -303,10 +303,13 @@ func (f FieldMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Lookup returns a PathGetter to lookup a field by its path.
|
||||
func Lookup(path ...string) PathGetter {
|
||||
return PathGetter{Path: path}
|
||||
}
|
||||
|
||||
// Lookup returns a PathGetter to lookup a field by its path and create it if it doesn't already
|
||||
// exist.
|
||||
func LookupCreate(kind yaml.Kind, path ...string) PathGetter {
|
||||
return PathGetter{Path: path, Create: kind}
|
||||
}
|
||||
|
||||
@@ -77,19 +77,19 @@ func (s set) Has(key string) bool {
|
||||
return found
|
||||
}
|
||||
|
||||
// whitelistedListSortKinds contains the set of kinds that are whitelisted
|
||||
// WhitelistedListSortKinds contains the set of kinds that are whitelisted
|
||||
// for sorting list field elements
|
||||
var WhitelistedListSortKinds = newSet(
|
||||
"CronJob", "DaemonSet", "Deployment", "Job", "ReplicaSet", "StatefulSet",
|
||||
"ValidatingWebhookConfiguration")
|
||||
|
||||
// whitelistedListSortApis contains the set of apis that are whitelisted for
|
||||
// WhitelistedListSortApis contains the set of apis that are whitelisted for
|
||||
// sorting list field elements
|
||||
var WhitelistedListSortApis = newSet(
|
||||
"apps/v1", "apps/v1beta1", "apps/v1beta2", "batch/v1", "batch/v1beta1",
|
||||
"extensions/v1beta1", "v1", "admissionregistration.k8s.io/v1beta1")
|
||||
|
||||
// whitelistedListSortFields contains json paths to list fields that should
|
||||
// WhitelistedListSortFields contains json paths to list fields that should
|
||||
// be sorted, and the field they should be sorted by
|
||||
var WhitelistedListSortFields = map[string]string{
|
||||
".spec.template.spec.containers": "name",
|
||||
|
||||
@@ -19,10 +19,12 @@ const (
|
||||
NullNodeTag = "!!null"
|
||||
)
|
||||
|
||||
// NullNode returns a RNode point represents a null; value
|
||||
func NullNode() *RNode {
|
||||
return NewRNode(&Node{Tag: NullNodeTag})
|
||||
}
|
||||
|
||||
// IsMissingOrNull returns true if the RNode is nil or contains and explicitly null value.
|
||||
func IsMissingOrNull(node *RNode) bool {
|
||||
if node == nil || node.YNode() == nil || node.YNode().Tag == NullNodeTag {
|
||||
return true
|
||||
@@ -30,6 +32,8 @@ func IsMissingOrNull(node *RNode) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the RNode is MissingOrNull, or is either a MappingNode with
|
||||
// no fields, or a SequenceNode with no elements.
|
||||
func IsEmpty(node *RNode) bool {
|
||||
if node == nil || node.YNode() == nil || node.YNode().Tag == NullNodeTag {
|
||||
return true
|
||||
@@ -118,7 +122,7 @@ func MustParse(value string) *RNode {
|
||||
return v
|
||||
}
|
||||
|
||||
// NewScalarRNode returns a new Scalar *RNode containing the provided value.
|
||||
// NewScalarRNode returns a new Scalar *RNode containing the provided scalar value.
|
||||
func NewScalarRNode(value string) *RNode {
|
||||
return &RNode{
|
||||
value: &yaml.Node{
|
||||
@@ -127,7 +131,7 @@ func NewScalarRNode(value string) *RNode {
|
||||
}}
|
||||
}
|
||||
|
||||
// NewListRNode returns a new List *RNode containing the provided value.
|
||||
// NewListRNode returns a new List *RNode containing the provided scalar values.
|
||||
func NewListRNode(values ...string) *RNode {
|
||||
seq := &RNode{value: &yaml.Node{Kind: yaml.SequenceNode}}
|
||||
for _, v := range values {
|
||||
@@ -139,7 +143,7 @@ func NewListRNode(values ...string) *RNode {
|
||||
return seq
|
||||
}
|
||||
|
||||
// NewRNode returns a new *RNode containing the provided value.
|
||||
// NewRNode returns a new RNode pointer containing the provided Node.
|
||||
func NewRNode(value *yaml.Node) *RNode {
|
||||
if value != nil {
|
||||
value.Style = 0
|
||||
@@ -147,7 +151,9 @@ func NewRNode(value *yaml.Node) *RNode {
|
||||
return &RNode{value: value}
|
||||
}
|
||||
|
||||
// GrepFilter may modify or walk the RNode.
|
||||
// Filter defines a function to manipulate an individual RNode such as by changing
|
||||
// its values, or returning a field.
|
||||
//
|
||||
// When possible, Filters should be serializable to yaml so that they can be described
|
||||
// declaratively as data.
|
||||
//
|
||||
@@ -212,30 +218,31 @@ func (m MapNodeSlice) Values() []*RNode {
|
||||
return values
|
||||
}
|
||||
|
||||
// ResourceMeta contains the metadata for a Resource.
|
||||
// ResourceMeta contains the metadata for a both Resource Type and Resource.
|
||||
type ResourceMeta struct {
|
||||
// ApiVersion is the apiVersion field of a Resource
|
||||
ApiVersion string `yaml:"apiVersion,omitempty"`
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
// Kind is the kind field of a Resource
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
// ObjectMeta is the metadata field of a Resource
|
||||
ObjectMeta `yaml:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
func NewResourceMeta(name string, typeMeta ResourceMeta) ResourceMeta {
|
||||
return ResourceMeta{
|
||||
Kind: typeMeta.Kind,
|
||||
ApiVersion: typeMeta.ApiVersion,
|
||||
ObjectMeta: ObjectMeta{Name: name},
|
||||
}
|
||||
}
|
||||
|
||||
// ObjectMeta contains metadata about a Resource
|
||||
type ObjectMeta struct {
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Namespace string `yaml:"namespace,omitempty"`
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
// Name is the metadata.name field of a Resource
|
||||
Name string `yaml:"name,omitempty"`
|
||||
// Namespace is the metadata.namespace field of a Resource
|
||||
Namespace string `yaml:"namespace,omitempty"`
|
||||
// Labels is the metadata.labels field of a Resource
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
// Annotations is the metadata.annotations field of a Resource.
|
||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
var MissingMetaError = errors.New("missing Resource metadata")
|
||||
|
||||
// GetMeta returns the ResourceMeta for a RNode
|
||||
func (rn *RNode) GetMeta() (ResourceMeta, error) {
|
||||
m := ResourceMeta{}
|
||||
b := &bytes.Buffer{}
|
||||
@@ -309,7 +316,7 @@ func (rn *RNode) YNode() *yaml.Node {
|
||||
return rn.value
|
||||
}
|
||||
|
||||
// SetYNode sets the yaml.Node value.
|
||||
// SetYNode sets the yaml.Node value on an RNode.
|
||||
func (rn *RNode) SetYNode(node *yaml.Node) {
|
||||
if rn.value == nil || node == nil {
|
||||
rn.value = node
|
||||
@@ -318,12 +325,13 @@ func (rn *RNode) SetYNode(node *yaml.Node) {
|
||||
*rn.value = *node
|
||||
}
|
||||
|
||||
// SetYNode sets the value on a Document.
|
||||
// AppendToFieldPath appends a field name to the FieldPath.
|
||||
func (rn *RNode) AppendToFieldPath(parts ...string) {
|
||||
rn.fieldPath = append(rn.fieldPath, parts...)
|
||||
}
|
||||
|
||||
// FieldPath returns the field path from the object root to rn. Does not include list indexes.
|
||||
// FieldPath returns the field path from the Resource root node, to rn.
|
||||
// Does not include list indexes.
|
||||
func (rn *RNode) FieldPath() []string {
|
||||
return rn.fieldPath
|
||||
}
|
||||
@@ -333,6 +341,7 @@ const (
|
||||
Flow = "Flow"
|
||||
)
|
||||
|
||||
// String returns a string valuer for a Node, applying the supplied formatting options
|
||||
func String(node *yaml.Node, opts ...string) (string, error) {
|
||||
if node == nil {
|
||||
return "", nil
|
||||
@@ -358,7 +367,7 @@ func String(node *yaml.Node, opts ...string) (string, error) {
|
||||
return val, err
|
||||
}
|
||||
|
||||
// NewScalarRNode returns the yaml NewScalarRNode representation of the RNode value.
|
||||
// String returns string representation of the RNode
|
||||
func (rn *RNode) String() (string, error) {
|
||||
if rn == nil {
|
||||
return "", nil
|
||||
@@ -366,6 +375,7 @@ func (rn *RNode) String() (string, error) {
|
||||
return String(rn.value)
|
||||
}
|
||||
|
||||
// MustString returns string representation of the RNode or panics if there is an error
|
||||
func (rn *RNode) MustString() string {
|
||||
s, err := rn.String()
|
||||
if err != nil {
|
||||
@@ -374,7 +384,7 @@ func (rn *RNode) MustString() string {
|
||||
return s
|
||||
}
|
||||
|
||||
// Content returns the value node's Content field.
|
||||
// Content returns Node Content field.
|
||||
func (rn *RNode) Content() []*yaml.Node {
|
||||
if rn == nil {
|
||||
return nil
|
||||
@@ -382,8 +392,8 @@ func (rn *RNode) Content() []*yaml.Node {
|
||||
return rn.YNode().Content
|
||||
}
|
||||
|
||||
// Fields returns the list of fields for a ResourceNode containing a MappingNode
|
||||
// value.
|
||||
// Fields returns the list of field names for a MappingNode.
|
||||
// Returns an error for non-MappingNodes.
|
||||
func (rn *RNode) Fields() ([]string, error) {
|
||||
if err := ErrorIfInvalid(rn, yaml.MappingNode); err != nil {
|
||||
return nil, err
|
||||
@@ -395,7 +405,8 @@ func (rn *RNode) Fields() ([]string, error) {
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
// Field returns the fieldName, fieldValue pair for MappingNodes. Returns nil for non-MappingNodes.
|
||||
// Field returns a fieldName, fieldValue pair for MappingNodes.
|
||||
// Returns nil for non-MappingNodes.
|
||||
func (rn *RNode) Field(field string) *MapNode {
|
||||
if rn.YNode().Kind != yaml.MappingNode {
|
||||
return nil
|
||||
@@ -409,7 +420,8 @@ func (rn *RNode) Field(field string) *MapNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
// VisitFields calls fn for each field in rn.
|
||||
// VisitFields calls fn for each field in the RNode.
|
||||
// Returns an error for non-MappingNodes.
|
||||
func (rn *RNode) VisitFields(fn func(node *MapNode) error) error {
|
||||
// get the list of srcFieldNames
|
||||
srcFieldNames, err := rn.Fields()
|
||||
@@ -426,8 +438,8 @@ func (rn *RNode) VisitFields(fn func(node *MapNode) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Elements returns a list of elements for a ResourceNode containing a
|
||||
// SequenceNode value.
|
||||
// Elements returns the list of elements in the RNode.
|
||||
// Returns an error for non-SequenceNodes.
|
||||
func (rn *RNode) Elements() ([]*RNode, error) {
|
||||
if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
|
||||
return nil, err
|
||||
@@ -439,6 +451,9 @@ func (rn *RNode) Elements() ([]*RNode, error) {
|
||||
return elements, nil
|
||||
}
|
||||
|
||||
// ElementValues returns a list of all observed values for a given field name in a
|
||||
// list of elements.
|
||||
// Returns error for non-SequenceNodes.
|
||||
func (rn *RNode) ElementValues(key string) ([]string, error) {
|
||||
if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
|
||||
return nil, err
|
||||
@@ -454,7 +469,7 @@ func (rn *RNode) ElementValues(key string) ([]string, error) {
|
||||
}
|
||||
|
||||
// Element returns the element in the list which contains the field matching the value.
|
||||
// Returns nil for non-SequenceNodes
|
||||
// Returns nil for non-SequenceNodes or if no Element matches.
|
||||
func (rn *RNode) Element(key, value string) *RNode {
|
||||
if rn.YNode().Kind != yaml.SequenceNode {
|
||||
return nil
|
||||
@@ -466,7 +481,8 @@ func (rn *RNode) Element(key, value string) *RNode {
|
||||
return elem
|
||||
}
|
||||
|
||||
// VisitElements calls fn for each element in the list.
|
||||
// VisitElements calls fn for each element in a SequenceNode.
|
||||
// Returns an error for non-SequenceNodes
|
||||
func (rn *RNode) VisitElements(fn func(node *RNode) error) error {
|
||||
elements, err := rn.Elements()
|
||||
if err != nil {
|
||||
@@ -481,14 +497,17 @@ func (rn *RNode) VisitElements(fn func(node *RNode) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssociativeSequencePaths is a map of paths to sequences that have associative keys.
|
||||
// AssociativeSequencePaths is a list of field names that may be used as associative keys
|
||||
// when merge Resources.
|
||||
// The order sets the precedence of the merge keys -- if multiple keys are present
|
||||
// in the list, then the FIRST key which ALL elements have is used as the
|
||||
// associative key.
|
||||
// in Resources in a list, then the FIRST key which ALL elements in the list have is used as the
|
||||
// associative key for merging that list.
|
||||
var AssociativeSequenceKeys = []string{
|
||||
"mountPath", "devicePath", "ip", "type", "topologyKey", "name", "containerPort",
|
||||
}
|
||||
|
||||
// IsAssociative returns true if all elements in the list contain an AssociativeSequenceKey
|
||||
// as a field.
|
||||
func IsAssociative(nodes []*RNode) bool {
|
||||
for i := range nodes {
|
||||
node := nodes[i]
|
||||
@@ -502,13 +521,13 @@ func IsAssociative(nodes []*RNode) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsAssociative returns true if the RNode is for an associative list.
|
||||
// IsAssociative returns true if the RNode contains an AssociativeSequenceKey as a field.
|
||||
func (rn *RNode) IsAssociative() bool {
|
||||
return rn.GetAssociativeKey() != ""
|
||||
}
|
||||
|
||||
// GetAssociativeKey returns the associative key used to merge the list, or "" if the
|
||||
// list is not associative.
|
||||
// GetAssociativeKey returns the AssociativeSequenceKey used to merge the elements in the
|
||||
// SequenceNode, or "" if the list is not associative.
|
||||
func (rn *RNode) GetAssociativeKey() string {
|
||||
// look for any associative keys in the first element
|
||||
for _, key := range AssociativeSequenceKeys {
|
||||
|
||||
Reference in New Issue
Block a user