yaml

package
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2020 License: Apache-2.0 Imports: 15 Imported by: 614

Documentation

Overview

Package yaml contains libraries for manipulating individual Kubernetes Resource Configuration as yaml, keeping yaml structure and comments.

Parsing Resources

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()]
Example
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
`)
if err != nil {
	log.Fatal(err)
}

containers, err := Parse(`
- name: nginx # first container
  image: nginx
- name: nginx2 # second container
  image: nginx2
`)
if err != nil {
	log.Fatal(err)
}

node, err := obj.Pipe(
	LookupCreate(SequenceNode, "spec", "template", "spec", "containers"),
	Append(containers.YNode().Content...))
if err != nil {
	log.Fatal(err)
}

fmt.Println(node.String())
fmt.Println(obj.String())
Output:

 <nil>
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
spec:
  template:
    spec:
      containers:
      - name: nginx # first container
        image: nginx
      - name: nginx2 # second container
        image: nginx2
 <nil>

Index

Examples

Constants

View Source
const (
	AnnotationsField = "annotations"
	APIVersionField  = "apiVersion"
	KindField        = "kind"
	MetadataField    = "metadata"
	NameField        = "name"
	NamespaceField   = "namespace"
	LabelsField      = "labels"
)

Field names

View Source
const (
	Trim = "Trim"
	Flow = "Flow"
)
View Source
const (
	StringTag = "!!str"
	BoolTag   = "!!bool"
	IntTag    = "!!int"
)
View Source
const (
	// NullNodeTag is the tag set for a yaml.Document that contains no data -- e.g. it isn't a
	// Map, Slice, Document, etc
	NullNodeTag = "!!null"
)

Variables

View Source
var AliasNode yaml.Kind = yaml.AliasNode
View Source
var AssociativeSequenceKeys = []string{"name"}

AssociativeSequenceKeys is a map of paths to sequences that have associative keys. The order sets the precedence of the merge keys -- if multiple keys are present 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. Only infer name as a merge key.

View Source
var DocumentNode yaml.Kind = yaml.DocumentNode
View Source
var DoubleQuotedStyle yaml.Style = yaml.DoubleQuotedStyle
View Source
var ErrMissingMetadata = fmt.Errorf("missing Resource metadata")
View Source
var FieldOrder = func() map[string]int {

	fo := map[string]int{}
	for i, f := range fieldSortOrder {
		fo[f] = i + 1
	}
	return fo
}()

FieldOrder indexes fields and maps them to relative precedence

View Source
var Filters = map[string]func() Filter{
	"AnnotationClearer": func() Filter { return &AnnotationClearer{} },
	"AnnotationGetter":  func() Filter { return &AnnotationGetter{} },
	"AnnotationSetter":  func() Filter { return &AnnotationSetter{} },
	"LabelSetter":       func() Filter { return &LabelSetter{} },
	"ElementAppender":   func() Filter { return &ElementAppender{} },
	"ElementMatcher":    func() Filter { return &ElementMatcher{} },
	"FieldClearer":      func() Filter { return &FieldClearer{} },
	"FilterMatcher":     func() Filter { return &FilterMatcher{} },
	"FieldMatcher":      func() Filter { return &FieldMatcher{} },
	"FieldSetter":       func() Filter { return &FieldSetter{} },
	"PathGetter":        func() Filter { return &PathGetter{} },
	"PathMatcher":       func() Filter { return &PathMatcher{} },
	"Parser":            func() Filter { return &Parser{} },
	"PrefixSetter":      func() Filter { return &PrefixSetter{} },
	"ValueReplacer":     func() Filter { return &ValueReplacer{} },
	"SuffixSetter":      func() Filter { return &SuffixSetter{} },
	"TeePiper":          func() Filter { return &TeePiper{} },
}

Filters is the list of serializable Pipeline Filters

View Source
var FlowStyle yaml.Style = yaml.FlowStyle
View Source
var FoldedStyle yaml.Style = yaml.FoldedStyle
View Source
var LiteralStyle yaml.Style = yaml.LiteralStyle
View Source
var MappingNode yaml.Kind = yaml.MappingNode
View Source
var Marshal = yaml.Marshal
View Source
var NewDecoder = yaml.NewDecoder
View Source
var NewEncoder = func(w io.Writer) *yaml.Encoder {
	e := yaml.NewEncoder(w)
	e.SetIndent(2)
	return e
}
View Source
var ScalarNode yaml.Kind = yaml.ScalarNode
View Source
var SequenceNode yaml.Kind = yaml.SequenceNode
View Source
var SingleQuotedStyle yaml.Style = yaml.SingleQuotedStyle
View Source
var TaggedStyle yaml.Style = yaml.TaggedStyle
View Source
var Unmarshal = yaml.Unmarshal
View Source
var WhitelistedListSortApis = newSet(
	"apps/v1", "apps/v1beta1", "apps/v1beta2", "batch/v1", "batch/v1beta1",
	"extensions/v1beta1", "v1", "admissionregistration.k8s.io/v1beta1")

WhitelistedListSortApis contains the set of apis that are whitelisted for sorting list field elements

View Source
var WhitelistedListSortFields = map[string]string{
	".spec.template.spec.containers": "name",
	".webhooks.rules.operations":     "",
}

WhitelistedListSortFields contains json paths to list fields that should be sorted, and the field they should be sorted by

View Source
var WhitelistedListSortKinds = newSet(
	"CronJob", "DaemonSet", "Deployment", "Job", "ReplicaSet", "StatefulSet",
	"ValidatingWebhookConfiguration")

WhitelistedListSortKinds contains the set of kinds that are whitelisted for sorting list field elements

Functions

func DoSerializationHacks added in v0.1.4

func DoSerializationHacks(node *yaml.Node)

DoSerializationHacks addresses a bug in yaml V3 upstream, it parses the yaml node, and rearranges the head comments of the children of sequence node. Refer to https://github.com/go-yaml/yaml/issues/587 for more details

func DoSerializationHacksOnNodes added in v0.1.4

func DoSerializationHacksOnNodes(nodes []*RNode)

func ErrorIfAnyInvalidAndNonNull

func ErrorIfAnyInvalidAndNonNull(kind yaml.Kind, rn ...*RNode) error

func ErrorIfInvalid

func ErrorIfInvalid(rn *RNode, kind yaml.Kind) error

func FormatNonStringStyle added in v0.0.6

func FormatNonStringStyle(node *Node, schema spec.Schema)

FormatNonStringStyle makes sure that values which parse as non-string values in yaml 1.1 are correctly formatted given the Schema type.

func GetValue added in v0.0.6

func GetValue(node *RNode) string

GetValue returns underlying yaml.Node Value field

func IncrementFieldIndex

func IncrementFieldIndex(i int) int

IncrementFieldIndex increments i to point to the next field name element in a slice of Contents.

func IsCreate

func IsCreate(kind yaml.Kind) bool

IsCreate returns true if kind is specified

func IsEmpty

func IsEmpty(node *RNode) bool

IsEmpty returns true if the RNode is MissingOrNull, or is either a MappingNode with no fields, or a SequenceNode with no elements.

func IsFieldEmpty

func IsFieldEmpty(node *MapNode) bool

func IsFieldNull

func IsFieldNull(node *MapNode) bool

func IsFoundOrError

func IsFoundOrError(rn *RNode, err error) bool

IsFoundOrError returns true if rn is found or err is non-nil

func IsListIndex

func IsListIndex(p string) bool

IsListIndex returns true if p is an index into a Val. e.g. [fieldName=fieldValue] e.g. [=primitiveValue]

func IsMissingOrError

func IsMissingOrError(rn *RNode, err error) bool

IsMissingOrError returns true if rn is NOT found or err is non-nil

func IsMissingOrNull

func IsMissingOrNull(node *RNode) bool

IsMissingOrNull returns true if the RNode is nil or contains and explicitly null value.

func IsNull

func IsNull(node *RNode) bool

func IsValueNonString added in v0.1.11

func IsValueNonString(value string) bool

func IsYaml1_1NonString added in v0.0.6

func IsYaml1_1NonString(node *Node) bool

IsYaml1_1NonString returns true if the value parses as a non-string value in yaml 1.1 when unquoted.

Note: yaml 1.2 uses different keywords than yaml 1.1. Example: yaml 1.2 interprets `field: on` and `field: "on"` as equivalent (both strings). However Yaml 1.1 interprets `field: on` as on being a bool and `field: "on"` as on being a string. If an input is read with `field: "on"`, and the style is changed from DoubleQuote to 0, it will change the type of the field from a string to a bool. For this reason, fields which are keywords in yaml 1.1 should never have their style changed, as it would break backwards compatibility with yaml 1.1 -- which is what is used by the Kubernetes apiserver.

func SplitIndexNameValue

func SplitIndexNameValue(p string) (string, string, error)

SplitIndexNameValue splits a lookup part Val index into the field name and field value to match. e.g. splits [name=nginx] into (name, nginx) e.g. splits [=-jar] into ("", jar)

func String

func String(node *yaml.Node, opts ...string) (string, error)

String returns a string value for a Node, applying the supplied formatting options

func UndoSerializationHacks added in v0.1.4

func UndoSerializationHacks(node *yaml.Node)

UndoSerializationHacks reverts the changes made by DoSerializationHacks Refer to https://github.com/go-yaml/yaml/issues/587 for more details

func UndoSerializationHacksOnNodes added in v0.1.4

func UndoSerializationHacksOnNodes(nodes []*RNode)

func UpdateFile added in v0.0.12

func UpdateFile(filter Filter, path string) error

UpdateFile reads the file at path, applies the filter to it, and write the result back. path must contain a exactly 1 resource (YAML).

func WriteFile added in v0.0.12

func WriteFile(node *RNode, path string) error

WriteFile writes a single Resource to a yaml file

Types

type AnnotationClearer

type AnnotationClearer struct {
	Kind string `yaml:"kind,omitempty"`
	Key  string `yaml:"key,omitempty"`
}

AnnotationClearer removes an annotation at metadata.annotations. Returns nil if the annotation or field does not exist.

func ClearAnnotation

func ClearAnnotation(key string) AnnotationClearer

func (AnnotationClearer) Filter

func (c AnnotationClearer) Filter(rn *RNode) (*RNode, error)

type AnnotationGetter

type AnnotationGetter struct {
	Kind  string `yaml:"kind,omitempty"`
	Key   string `yaml:"key,omitempty"`
	Value string `yaml:"value,omitempty"`
}

AnnotationGetter gets an annotation at metadata.annotations. Returns nil if metadata.annotations does not exist.

func GetAnnotation

func GetAnnotation(key string) AnnotationGetter

func (AnnotationGetter) Filter

func (g AnnotationGetter) Filter(rn *RNode) (*RNode, error)

AnnotationGetter returns the annotation value. Returns "", nil if the annotation does not exist.

type AnnotationSetter

type AnnotationSetter struct {
	Kind  string `yaml:"kind,omitempty"`
	Key   string `yaml:"key,omitempty"`
	Value string `yaml:"value,omitempty"`
}

AnnotationSetter sets an annotation at metadata.annotations. Creates metadata.annotations if does not exist.

func SetAnnotation

func SetAnnotation(key, value string) AnnotationSetter

func (AnnotationSetter) Filter

func (s AnnotationSetter) Filter(rn *RNode) (*RNode, error)

type Decoder

type Decoder = yaml.Decoder

type ElementAppender

type ElementAppender struct {
	Kind string `yaml:"kind,omitempty"`

	// Elem is the value to append.
	Elements []*yaml.Node `yaml:"elements,omitempty"`
}

ElementAppender adds all element to a SequenceNode's Content. Returns Elements[0] if len(Elements) == 1, otherwise returns nil.

func Append

func Append(elements ...*yaml.Node) ElementAppender

Append creates an ElementAppender

Example (AppendMap)
obj, err := Parse(`
- name: foo
- name: bar
`)
if err != nil {
	log.Fatal(err)
}
elem, err := Parse("name: baz")
if err != nil {
	log.Fatal(err)
}
node, err := obj.Pipe(Append(elem.YNode()))
if err != nil {
	log.Fatal(err)
}

// Expect the node to contain the appended element because only
// 1 element was appended
fmt.Println(node.String())
fmt.Println(obj.String())
Output:

name: baz
 <nil>
- name: foo
- name: bar
- name: baz
 <nil>
Example (AppendScalars)
obj, err := Parse(`
- a
- b
`)
if err != nil {
	log.Fatal(err)
}
_, err = obj.Pipe(Append(&Node{Value: "c", Kind: ScalarNode}))
if err != nil {
	log.Fatal(err)
}
node, err := obj.Pipe(Append(
	&Node{Value: "c", Kind: ScalarNode},
	&Node{Value: "d", Kind: ScalarNode},
))
if err != nil {
	log.Fatal(err)
}
fmt.Println(node.String())
fmt.Println(obj.String())
Output:

 <nil>
- a
- b
- c
- c
- d
 <nil>

func (ElementAppender) Filter

func (a ElementAppender) Filter(rn *RNode) (*RNode, error)

type ElementMatcher

type ElementMatcher struct {
	Kind string `yaml:"kind,omitempty"`

	// FieldName will attempt to match this field in each list element.
	// Optional.  Leave empty for lists of primitives (ScalarNode).
	FieldName string `yaml:"name,omitempty"`

	// FieldValue will attempt to match each element field to this value.
	// For lists of primitives, this will be used to match the primitive value.
	FieldValue string `yaml:"value,omitempty"`

	// Create will create the Element if it is not found
	Create *RNode `yaml:"create,omitempty"`
}

ElementMatcher returns the first element from a Sequence matching the specified field's value.

func MatchElement

func MatchElement(field, value string) ElementMatcher

func (ElementMatcher) Filter

func (e ElementMatcher) Filter(rn *RNode) (*RNode, error)
Example
obj, err := Parse(`
- a
- b
`)
if err != nil {
	log.Fatal(err)
}
elem, err := obj.Pipe(ElementMatcher{
	FieldValue: "c", Create: NewScalarRNode("c"),
})
if err != nil {
	log.Fatal(err)
}

fmt.Println(elem.String())
fmt.Println(obj.String())
Output:

c
 <nil>
- a
- b
- c
 <nil>
Example (ObjectFound)
obj, err := Parse(`
- name: foo
- name: bar
- name: baz
`)
if err != nil {
	log.Fatal(err)
}
append, err := Parse(`
name: baz
image: nginx
`)
if err != nil {
	log.Fatal(err)
}
elem, err := obj.Pipe(ElementMatcher{
	FieldName: "name", FieldValue: "baz", Create: append})
if err != nil {
	log.Fatal(err)
}
fmt.Println(elem.String())
fmt.Println(obj.String())
Output:

name: baz
 <nil>
- name: foo
- name: bar
- name: baz
 <nil>
Example (ObjectNotFound)
obj, err := Parse(`
- name: foo
- name: bar
`)
if err != nil {
	log.Fatal(err)
}
append, err := Parse(`
name: baz
image: nginx
`)
if err != nil {
	log.Fatal(err)
}
elem, err := obj.Pipe(ElementMatcher{
	FieldName: "name", FieldValue: "baz", Create: append})
if err != nil {
	log.Fatal(err)
}
fmt.Println(elem.String())
fmt.Println(obj.String())
Output:

name: baz
image: nginx
 <nil>
- name: foo
- name: bar
- name: baz
  image: nginx
 <nil>
Example (PrimitiveFound)
obj, err := Parse(`
- a
- b
- c
`)
if err != nil {
	log.Fatal(err)
}
elem, err := obj.Pipe(ElementMatcher{
	FieldValue: "c", Create: NewScalarRNode("c"),
})
if err != nil {
	log.Fatal(err)
}
fmt.Println(elem.String())
fmt.Println(obj.String())
Output:

c
 <nil>
- a
- b
- c
 <nil>

type ElementSetter

type ElementSetter struct {
	Kind string `yaml:"kind,omitempty"`

	// Element is the new value to set -- remove the existing element if nil
	Element *Node

	// Key is a field on the elements.  It is used to find the matching element to
	// update / delete.
	Key string `yaml:"key,omitempty"`

	// Value is a field value on the elements.  It is used to find matching elements to
	// update / delete.
	Value string `yaml:"value,omitempty"`
}

ElementSetter sets the value for an Element in an associative list. ElementSetter will remove any elements which are empty.

func (ElementSetter) Filter

func (e ElementSetter) Filter(rn *RNode) (*RNode, error)

type Encoder

type Encoder = yaml.Encoder

type FieldClearer

type FieldClearer struct {
	Kind string `yaml:"kind,omitempty"`

	// Name is the name of the field or key in the map.
	Name string `yaml:"name,omitempty"`

	IfEmpty bool `yaml:"ifEmpty,omitempty"`
}

FieldClearer removes the field or map key. Returns a RNode with the removed field or map entry.

func Clear

func Clear(name string) FieldClearer

Clear returns a FieldClearer

Example
obj, err := Parse(`
kind: Deployment
metadata:
  name: app
  annotations:
    a.b.c: d.e.f
    g: h
spec:
  template: {}
`)
if err != nil {
	log.Fatal(err)
}
node, err := obj.Pipe(Clear("metadata"))
if err != nil {
	log.Fatal(err)
}
fmt.Println(node.String())
fmt.Println(obj.String())
Output:

name: app
annotations:
  a.b.c: d.e.f
  g: h
 <nil>
kind: Deployment
spec:
  template: {}
 <nil>

func (FieldClearer) Filter

func (c FieldClearer) Filter(rn *RNode) (*RNode, error)

type FieldMatcher

type FieldMatcher struct {
	Kind string `yaml:"kind,omitempty"`

	// Name of the field to return
	Name string `yaml:"name,omitempty"`

	// YNode of the field to return.
	// Optional.  Will only need to match field name if unset.
	Value *RNode `yaml:"value,omitempty"`

	StringValue string `yaml:"stringValue,omitempty"`

	StringRegexValue string `yaml:"stringRegexValue,omitempty"`

	// Create will cause the field to be created with this value
	// if it is set.
	Create *RNode `yaml:"create,omitempty"`
}

FieldMatcher returns the value of a named field or map entry.

func Get

func Get(name string) FieldMatcher
Example
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  annotations:
    a.b.c: d.e.f
    g: h
spec:
  template: {}
`)
if err != nil {
	log.Fatal(err)
}
node, err := obj.Pipe(Get("metadata"))
if err != nil {
	log.Fatal(err)
}
fmt.Println(node.String())
fmt.Println(obj.String())
Output:

name: app
annotations:
  a.b.c: d.e.f
  g: h
 <nil>
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  annotations:
    a.b.c: d.e.f
    g: h
spec:
  template: {}
 <nil>
Example (NotFound)
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
spec:
  template: {}
`)
if err != nil {
	log.Fatal(err)
}
node, err := obj.Pipe(FieldMatcher{Name: "metadata"})
if err != nil {
	log.Fatal(err)
}
fmt.Println(node.String())
fmt.Println(obj.String())
Output:

 <nil>
apiVersion: apps/v1
kind: Deployment
spec:
  template: {}
 <nil>

func Match

func Match(value string) FieldMatcher

func MatchField

func MatchField(name, value string) FieldMatcher

func (FieldMatcher) Filter

func (f FieldMatcher) Filter(rn *RNode) (*RNode, error)
Example
obj, err := Parse(`
kind: Deployment
spec:
  template: {}
`)
if err != nil {
	log.Fatal(err)
}
value, err := Parse(`
name: app
annotations:
  a.b.c: d.e.f
  g: h
`)
if err != nil {
	log.Fatal(err)
}
elem, err := obj.Pipe(FieldMatcher{
	Name: "metadata", Value: value, Create: value})
if err != nil {
	log.Fatal(err)
}
fmt.Println(elem.String())
fmt.Println(obj.String())
Output:

name: app
annotations:
  a.b.c: d.e.f
  g: h
 <nil>
kind: Deployment
spec:
  template: {}
metadata:
  name: app
  annotations:
    a.b.c: d.e.f
    g: h
 <nil>

type FieldSetter

type FieldSetter struct {
	Kind string `yaml:"kind,omitempty"`

	// Name is the name of the field or key to lookup in a MappingNode.
	// If Name is unspecified, and the input is a ScalarNode, FieldSetter will set the
	// value on the ScalarNode.
	Name string `yaml:"name,omitempty"`

	// Value is the value to set.
	// Optional if Kind is set.
	Value *RNode `yaml:"value,omitempty"`

	StringValue string `yaml:"stringValue,omitempty"`

	// OverrideStyle can be set to override the style of the existing node
	// when setting it.  Otherwise, if an existing node is found, the style is
	// retained.
	OverrideStyle bool `yaml:"overrideStyle,omitempty"`
}

FieldSetter sets a field or map entry to a value.

func Set

func Set(value *RNode) FieldSetter

func SetField

func SetField(name string, value *RNode) FieldSetter
Example
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
`)
if err != nil {
	log.Fatal(err)
}

containers, err := Parse(`
- name: nginx # first container
  image: nginx
- name: nginx2 # second container
  image: nginx2
`)
if err != nil {
	log.Fatal(err)
}

_, err = obj.Pipe(
	LookupCreate(MappingNode, "spec", "template", "spec"),
	SetField("containers", containers))
if err != nil {
	log.Fatal(err)
}

fmt.Println(obj.String())
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
spec:
  template:
    spec:
      containers:
      - name: nginx # first container
        image: nginx
      - name: nginx2 # second container
        image: nginx2
 <nil>
Example (StringValue)
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
metadata:
 name: app
`)
if err != nil {
	log.Fatal(err)
}
_, err = obj.Pipe(SetField("foo", NewScalarRNode("bar")))
if err != nil {
	log.Fatal(err)
}

fmt.Println(obj.String())
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
foo: bar
 <nil>
Example (StringValueOverwrite)
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
metadata:
   name: app
foo: baz
`)
if err != nil {
	// handle error
}
// set metadata.annotations.foo = bar
_, err = obj.Pipe(SetField("foo", NewScalarRNode("bar")))
if err != nil {
	// handle error
}

fmt.Println(obj.String())
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
foo: bar
 <nil>

func (FieldSetter) Filter

func (s FieldSetter) Filter(rn *RNode) (*RNode, error)

type Filter

type Filter interface {
	Filter(object *RNode) (*RNode, error)
}

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.

Analogous to http://www.linfo.org/filters.html

func Tee

func Tee(filters ...Filter) Filter

Tee calls the provided Filters, and returns its argument rather than the result of the filters. May be used to fork sub-filters from a call. e.g. locate field, set value; locate another field, set another value

Example
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
`)
if err != nil {
	// handle error
}
// set metadata.annotations.foo = bar
_, err = obj.Pipe(
	Lookup("spec", "template", "spec", "containers", "[name=nginx]"),
	Tee(SetField("filter", NewListRNode("foo"))),
	SetField("args", NewListRNode("baz", "bar")))
if err != nil {
	// handle error
}

fmt.Println(obj.String())
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
        filter:
        - foo
        args:
        - baz
        - bar
 <nil>

type FilterFunc

type FilterFunc func(object *RNode) (*RNode, error)

func (FilterFunc) Filter

func (f FilterFunc) Filter(object *RNode) (*RNode, error)

type FilterMatcher

type FilterMatcher struct {
	Kind string `yaml:"kind"`

	// Filters are the set of Filters run by TeePiper.
	Filters YFilters `yaml:"pipeline,omitempty"`
}

func (FilterMatcher) Filter

func (t FilterMatcher) Filter(rn *RNode) (*RNode, error)

type IsZeroer

type IsZeroer = yaml.IsZeroer

type Kind

type Kind = yaml.Kind

type LabelSetter added in v0.1.1

type LabelSetter struct {
	Kind  string `yaml:"kind,omitempty"`
	Key   string `yaml:"key,omitempty"`
	Value string `yaml:"value,omitempty"`
}

LabelSetter sets a label at metadata.labels. Creates metadata.labels if does not exist.

func SetLabel added in v0.1.1

func SetLabel(key, value string) LabelSetter

func (LabelSetter) Filter added in v0.1.1

func (s LabelSetter) Filter(rn *RNode) (*RNode, error)

type MapNode

type MapNode struct {
	Key   *RNode
	Value *RNode
}

MapNode wraps a field key and value.

type MapNodeSlice

type MapNodeSlice []*MapNode

func (MapNodeSlice) Keys

func (m MapNodeSlice) Keys() []*RNode

func (MapNodeSlice) Values

func (m MapNodeSlice) Values() []*RNode

type Marshaler

type Marshaler = yaml.Marshaler

type Node

type Node = yaml.Node

type ObjectMeta

type ObjectMeta struct {
	// 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"`
}

ObjectMeta contains metadata about a Resource

type Parser

type Parser struct {
	Kind  string `yaml:"kind,omitempty"`
	Value string `yaml:"value,omitempty"`
}

Parser parses values into configuration.

func (Parser) Filter

func (p Parser) Filter(_ *RNode) (*RNode, error)

type PathGetter

type PathGetter struct {
	Kind string `yaml:"kind,omitempty"`

	// Path is a slice of parts leading to the RNode to lookup.
	// Each path part may be one of:
	// * FieldMatcher -- e.g. "spec"
	// * Map Key -- e.g. "app.k8s.io/version"
	// * List Entry -- e.g. "[name=nginx]" or "[=-jar]"
	//
	// Map Keys and Fields are equivalent.
	// See FieldMatcher for more on Fields and Map Keys.
	//
	// List Entries are specified as map entry to match [fieldName=fieldValue].
	// See Elem for more on List Entries.
	//
	// Examples:
	// * spec.template.spec.container with matching name: [name=nginx]
	// * spec.template.spec.container.argument matching a value: [=-jar]
	Path []string `yaml:"path,omitempty"`

	// Create will cause missing path parts to be created as they are walked.
	//
	// * The leaf Node (final path) will be created with a Kind matching Create
	// * Intermediary Nodes will be created as either a MappingNodes or
	//   SequenceNodes as appropriate for each's Path location.
	Create yaml.Kind `yaml:"create,omitempty"`

	// Style is the style to apply to created value Nodes.
	// Created key Nodes keep an unspecified Style.
	Style yaml.Style `yaml:"style,omitempty"`
}

PathGetter returns the RNode under Path.

func Lookup

func Lookup(path ...string) PathGetter

Lookup returns a PathGetter to lookup a field by its path.

Example (Element)
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
spec:
  templates:
    spec:
      containers:
      - name: nginx
        image: nginx:latest
`)
if err != nil {
	log.Fatal(err)
}
value, err := obj.Pipe(Lookup(
	"spec", "templates", "spec", "containers", "[name=nginx]"))
if err != nil {
	log.Fatal(err)
}

fmt.Println(value.String())
Output:

name: nginx
image: nginx:latest
 <nil>
Example (NotFound)
obj, err := Parse(`
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
`)
if err != nil {
	log.Fatal(err)
}
rs, err := obj.Pipe(Lookup("spec", "templates", "spec"))
if err != nil {
	log.Fatal(err)
}

fmt.Println(rs)
fmt.Println("---")
fmt.Println(obj.String())
Output:

 <nil>
---
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
 <nil>
Example (Scalar)
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
spec:
  templates:
    spec:
      containers:
      - name: nginx
        image: nginx:latest
`)
if err != nil {
	log.Fatal(err)
}
value, err := obj.Pipe(Lookup(
	"spec", "templates", "spec", "containers", "[name=nginx]", "image"))
if err != nil {
	log.Fatal(err)
}

fmt.Println(value.String())
Output:

nginx:latest
 <nil>
Example (Sequence)
obj, err := Parse(`apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
     app: java
  annotations:
    a.b.c: d.e.f
  name: app
spec:
  templates:
    spec:
      containers:
      - name: nginx
        image: nginx:latest
`)
if err != nil {
	log.Fatal(err)
}
value, err := obj.Pipe(Lookup(
	"spec", "templates", "spec", "containers"))
if err != nil {
	log.Fatal(err)
}

fmt.Println(value.String())
Output:

- name: nginx
  image: nginx:latest
 <nil>

func LookupCreate

func LookupCreate(kind yaml.Kind, path ...string) PathGetter

Lookup returns a PathGetter to lookup a field by its path and create it if it doesn't already exist.

Example (Element)
obj, err := Parse(`
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
`)
if err != nil {
	log.Fatal(err)
}
rs, err := obj.Pipe(LookupCreate(
	MappingNode, "spec", "templates", "spec", "containers", "[name=nginx]"))
if err != nil {
	log.Fatal(err)
}

fmt.Println(rs.String())
fmt.Println("---")
fmt.Println(obj.String())
Output:

name: nginx
 <nil>
---
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
spec:
  templates:
    spec:
      containers:
      - name: nginx
 <nil>
Example (Object)
obj, err := Parse(`
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
`)
if err != nil {
	log.Fatal(err)
}
rs, err := obj.Pipe(LookupCreate(
	MappingNode, "spec", "templates", "spec"))
if err != nil {
	log.Fatal(err)
}

fmt.Println(rs.String())
fmt.Println("---")
fmt.Println(obj.String())
Output:

{}
 <nil>
---
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
spec:
  templates:
    spec: {}
 <nil>
Example (Sequence)
obj, err := Parse(`
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
`)
if err != nil {
	log.Fatal(err)
}
rs, err := obj.Pipe(LookupCreate(
	SequenceNode, "spec", "templates", "spec", "containers"))
if err != nil {
	log.Fatal(err)
}

fmt.Println(rs.String())
fmt.Println("---")
fmt.Println(obj.String())
Output:

[]
 <nil>
---
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
spec:
  templates:
    spec:
      containers: []
 <nil>

func (PathGetter) Filter

func (l PathGetter) Filter(rn *RNode) (*RNode, error)
Example
obj, err := Parse(`
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
`)
if err != nil {
	log.Fatal(err)
}
rs, err := obj.Pipe(PathGetter{
	Path:   []string{"spec", "templates", "spec", "containers", "[name=nginx]", "image"},
	Create: ScalarNode,
})
if err != nil {
	log.Fatal(err)
}
rs.Document().Style = SingleQuotedStyle

fmt.Println(rs.String())
fmt.Println("---")
fmt.Println(obj.String())
Output:

''
 <nil>
---
kind: Deployment
metadata:
  labels:
    app: java
  annotations:
    a.b.c: d.e.f
  name: app
spec:
  templates:
    spec:
      containers:
      - name: nginx
        image: ''
 <nil>

type PathMatcher

type PathMatcher struct {
	Kind string `yaml:"kind,omitempty"`

	// Path is a slice of parts leading to the RNode to lookup.
	// Each path part may be one of:
	// * FieldMatcher -- e.g. "spec"
	// * Map Key -- e.g. "app.k8s.io/version"
	// * List Entry -- e.g. "[name=nginx]" or "[=-jar]"
	//
	// Map Keys and Fields are equivalent.
	// See FieldMatcher for more on Fields and Map Keys.
	//
	// List Entries are specified as map entry to match [fieldName=fieldValue].
	// See Elem for more on List Entries.
	//
	// Examples:
	// * spec.template.spec.container with matching name: [name=nginx] -- match 'name': 'nginx'
	// * spec.template.spec.container.argument matching a value: [=-jar] -- match '-jar'
	Path []string `yaml:"path,omitempty"`

	// Matches is set by PathMatch to publish the matched element values for each node.
	// After running  PathMatcher.Filter, each node from the SequenceNode result may be
	// looked up in Matches to find the field values that were matched.
	Matches map[*Node][]string

	// StripComments may be set to remove the comments on the matching Nodes.
	// This is useful for if the nodes are to be printed in FlowStyle.
	StripComments bool
	// contains filtered or unexported fields
}

PathMatcher returns all RNodes matching the path wrapped in a SequenceNode. Lists may have multiple elements matching the path, and each matching element is added to the return result. If Path points to a SequenceNode, the SequenceNode is wrapped in another SequenceNode If Path does not contain any lists, the result is still wrapped in a SequenceNode of len == 1

func (*PathMatcher) Filter

func (p *PathMatcher) Filter(rn *RNode) (*RNode, error)

type PrefixSetter

type PrefixSetter struct {
	Kind string `yaml:"kind"`

	Value string `yaml:"value"`
}

func (PrefixSetter) Filter

func (s PrefixSetter) Filter(object *RNode) (*RNode, error)

type RNode

type RNode struct {
	Match []string
	// contains filtered or unexported fields
}

RNode provides functions for manipulating Kubernetes Resources Objects unmarshalled into *yaml.Nodes

func ConvertJSONToYamlNode added in v0.1.12

func ConvertJSONToYamlNode(jsonStr string) (*RNode, error)

ConvertJSONToYamlNode parses input json string and returns equivalent yaml node

func MustParse

func MustParse(value string) *RNode

MustParse parses a yaml string into an *RNode and panics if there is an error

func NewListRNode

func NewListRNode(values ...string) *RNode

NewListRNode returns a new List *RNode containing the provided scalar values.

func NewRNode

func NewRNode(value *yaml.Node) *RNode

NewRNode returns a new RNode pointer containing the provided Node.

func NewScalarRNode

func NewScalarRNode(value string) *RNode

NewScalarRNode returns a new Scalar *RNode containing the provided scalar value.

func NullNode

func NullNode() *RNode

NullNode returns a RNode point represents a null; value

func Parse

func Parse(value string) (*RNode, error)

Parse parses a yaml string into an *RNode

func ReadFile added in v0.0.12

func ReadFile(path string) (*RNode, error)

ReadFile parses a single Resource from a yaml file

func (*RNode) AppendToFieldPath

func (rn *RNode) AppendToFieldPath(parts ...string)

AppendToFieldPath appends a field name to the FieldPath.

func (*RNode) Content

func (rn *RNode) Content() []*yaml.Node

Content returns Node Content field.

func (*RNode) Document

func (rn *RNode) Document() *yaml.Node

Document returns the Node RNode for the value. Does not unwrap the node if it is a DocumentNodes

func (*RNode) Element

func (rn *RNode) Element(key, value string) *RNode

Element returns the element in the list which contains the field matching the value. Returns nil for non-SequenceNodes or if no Element matches.

func (*RNode) ElementValues

func (rn *RNode) ElementValues(key string) ([]string, error)

ElementValues returns a list of all observed values for a given field name in a list of elements. Returns error for non-SequenceNodes.

Example
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>

func (*RNode) Elements

func (rn *RNode) Elements() ([]*RNode, error)

Elements returns the list of elements in the RNode. Returns an error for non-SequenceNodes.

Example
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.Printf("Element: %d\n", 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 (*RNode) Field

func (rn *RNode) Field(field string) *MapNode

Field returns a fieldName, fieldValue pair for MappingNodes. Returns nil for non-MappingNodes.

func (*RNode) FieldPath

func (rn *RNode) FieldPath() []string

FieldPath returns the field path from the Resource root node, to rn. Does not include list indexes.

func (*RNode) Fields

func (rn *RNode) Fields() ([]string, error)

Fields returns the list of field names for a MappingNode. Returns an error for non-MappingNodes.

func (*RNode) GetAssociativeKey

func (rn *RNode) GetAssociativeKey() string

GetAssociativeKey returns the AssociativeSequenceKey used to merge the elements in the SequenceNode, or "" if the list is not associative.

func (*RNode) GetMeta

func (rn *RNode) GetMeta() (ResourceMeta, error)

GetMeta returns the ResourceMeta for an RNode

func (*RNode) IsAssociative

func (rn *RNode) IsAssociative() bool

IsAssociative returns true if the RNode contains an AssociativeSequenceKey as a field.

func (*RNode) MarshalJSON added in v0.1.5

func (rn *RNode) MarshalJSON() ([]byte, error)

func (*RNode) MustString

func (rn *RNode) MustString() string

MustString returns string representation of the RNode or panics if there is an error

func (*RNode) Pipe

func (rn *RNode) Pipe(functions ...Filter) (*RNode, error)

Pipe sequentially invokes each GrepFilter, and passes the result to the next GrepFilter.

Analogous to http://www.linfo.org/pipes.html

* rn is provided as input to the first GrepFilter. * if any GrepFilter returns an error, immediately return the error * if any GrepFilter returns a nil RNode, immediately return nil, nil * if all Filters succeed with non-empty results, return the final result

func (*RNode) PipeE

func (rn *RNode) PipeE(functions ...Filter) error

PipeE runs Pipe, dropping the *RNode return value. Useful for directly returning the Pipe error value from functions.

func (*RNode) SetYNode

func (rn *RNode) SetYNode(node *yaml.Node)

SetYNode sets the yaml.Node value on an RNode.

func (*RNode) String

func (rn *RNode) String() (string, error)

String returns string representation of the RNode

func (*RNode) UnmarshalJSON added in v0.1.5

func (rn *RNode) UnmarshalJSON(b []byte) error

func (*RNode) VisitElements

func (rn *RNode) VisitElements(fn func(node *RNode) error) error

VisitElements calls fn for each element in a SequenceNode. Returns an error for non-SequenceNodes

func (*RNode) VisitFields

func (rn *RNode) VisitFields(fn func(node *MapNode) error) error

VisitFields calls fn for each field in the RNode. Returns an error for non-MappingNodes.

func (*RNode) YNode

func (rn *RNode) YNode() *yaml.Node

YNode returns the yaml.Node value. If the yaml.Node value is a DocumentNode, YNode will return the DocumentNode Content entry instead of the DocumentNode.

type ResourceIdentifier

type ResourceIdentifier struct {
	// Name is the name of the resource as set in metadata.name
	Name string `yaml:"name,omitempty"`
	// Namespace is the namespace of the resource as set in metadata.namespace
	Namespace string `yaml:"namespace,omitempty"`
	// ApiVersion is the apiVersion of the resource
	APIVersion string `yaml:"apiVersion,omitempty"`
	// Kind is the kind of the resource
	Kind string `yaml:"kind,omitempty"`
}

ResourceIdentifier contains the information needed to uniquely identify a resource in a cluster.

func (*ResourceIdentifier) GetAPIVersion

func (r *ResourceIdentifier) GetAPIVersion() string

func (*ResourceIdentifier) GetKind

func (r *ResourceIdentifier) GetKind() string

func (*ResourceIdentifier) GetName

func (r *ResourceIdentifier) GetName() string

func (*ResourceIdentifier) GetNamespace

func (r *ResourceIdentifier) GetNamespace() string

type ResourceMeta

type ResourceMeta struct {
	// APIVersion is the apiVersion field of a Resource
	APIVersion string `yaml:"apiVersion,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"`
}

ResourceMeta contains the metadata for a both Resource Type and Resource.

func (*ResourceMeta) GetIdentifier

func (m *ResourceMeta) GetIdentifier() ResourceIdentifier

GetIdentifier returns a ResourceIdentifier that includes the information needed to uniquely identify a resource in a cluster.

type Style

type Style = yaml.Style

func GetStyle

func GetStyle(styles ...string) Style

TODO(pwittrock): test this

type SuffixSetter

type SuffixSetter struct {
	Kind string `yaml:"kind"`

	Value string `yaml:"value"`
}

func (SuffixSetter) Filter

func (s SuffixSetter) Filter(object *RNode) (*RNode, error)

type TeePiper

type TeePiper struct {
	Kind string `yaml:"kind,omitempty"`

	// Filters are the set of Filters run by TeePiper.
	Filters []Filter `yaml:"filters,omitempty"`
}

TeePiper Calls a slice of Filters and returns its input. May be used to fork sub-filters from a call. e.g. locate field, set value; locate another field, set another value

func (TeePiper) Filter

func (t TeePiper) Filter(rn *RNode) (*RNode, error)

type TypeError

type TypeError = yaml.TypeError

type TypeMeta added in v0.0.6

type TypeMeta struct {
	Kind       string
	APIVersion string
}

type Unmarshaler

type Unmarshaler = yaml.Unmarshaler

type ValueReplacer

type ValueReplacer struct {
	Kind string `yaml:"kind"`

	StringMatch string `yaml:"stringMatch"`
	RegexMatch  string `yaml:"regexMatch"`
	Replace     string `yaml:"replace"`
	Count       int    `yaml:"count"`
}

func (ValueReplacer) Filter

func (s ValueReplacer) Filter(object *RNode) (*RNode, error)

type YFilter

type YFilter struct {
	Filter
}

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.

func (YFilter) MarshalYAML

func (y YFilter) MarshalYAML() (interface{}, error)

func (*YFilter) UnmarshalYAML

func (y *YFilter) UnmarshalYAML(unmarshal func(interface{}) error) error

type YFilters

type YFilters []YFilter

func (YFilters) Filters

func (y YFilters) Filters() []Filter

Directories

Path Synopsis
Package merge contains libraries for merging fields from one RNode to another RNode
Package merge contains libraries for merging fields from one RNode to another RNode
Package merge contains libraries for merging fields from one RNode to another RNode
Package merge contains libraries for merging fields from one RNode to another RNode
Package schema contains libraries for working with the yaml and openapi packages.
Package schema contains libraries for working with the yaml and openapi packages.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL