use kyaml filters

This commit is contained in:
ultram4rine 2023-12-24 04:11:23 +04:00
parent 6013c023be
commit eee058119b
5 changed files with 74 additions and 129 deletions

View File

@ -15,7 +15,8 @@
package kubeconfig package kubeconfig
import ( import (
"github.com/pkg/errors" "errors"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
@ -24,60 +25,34 @@ func (k *Kubeconfig) DeleteContextEntry(deleteName string) error {
if err != nil { if err != nil {
return err return err
} }
if err := contexts.PipeE(
i := -1 yaml.ElementSetter{
for j, ctxNode := range contexts.Content { Keys: []string{"name"},
nameNode := valueOf(ctxNode, "name") Values: []string{deleteName},
if nameNode != nil && nameNode.Kind == yaml.ScalarNode && nameNode.Value == deleteName { },
i = j ); err != nil {
break return err
}
}
if i >= 0 {
copy(contexts.Content[i:], contexts.Content[i+1:])
contexts.Content[len(contexts.Content)-1] = nil
contexts.Content = contexts.Content[:len(contexts.Content)-1]
} }
return nil return nil
} }
func (k *Kubeconfig) ModifyCurrentContext(name string) error { func (k *Kubeconfig) ModifyCurrentContext(name string) error {
currentCtxNode := valueOf(k.rootNode, "current-context") if err := k.config.PipeE(yaml.SetField("current-context", yaml.NewScalarRNode(name))); err != nil {
if currentCtxNode != nil { return err
currentCtxNode.Value = name
return nil
} }
// if current-context field doesn't exist, create new field
keyNode := &yaml.Node{
Kind: yaml.ScalarNode,
Value: "current-context",
Tag: "!!str"}
valueNode := &yaml.Node{
Kind: yaml.ScalarNode,
Value: name,
Tag: "!!str"}
k.rootNode.Content = append(k.rootNode.Content, keyNode, valueNode)
return nil return nil
} }
func (k *Kubeconfig) ModifyContextName(old, new string) error { func (k *Kubeconfig) ModifyContextName(old, new string) error {
contexts, err := k.contextsNode() context, err := k.config.Pipe(yaml.Lookup("contexts", "[name="+old+"]"))
if err != nil { if err != nil {
return err return err
} }
if context == nil {
var changed bool return errors.New("\"contexts\" entry is nil")
for _, contextNode := range contexts.Content {
nameNode := valueOf(contextNode, "name")
if nameNode.Kind == yaml.ScalarNode && nameNode.Value == old {
nameNode.Value = new
changed = true
break
}
} }
if !changed { if err := context.PipeE(yaml.SetField("name", yaml.NewScalarRNode(new))); err != nil {
return errors.New("no changes were made") return err
} }
return nil return nil
} }

View File

@ -19,48 +19,40 @@ import (
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
func (k *Kubeconfig) contextsNode() (*yaml.Node, error) { func (k *Kubeconfig) contextsNode() (*yaml.RNode, error) {
contexts := valueOf(k.rootNode, "contexts") contexts, err := k.config.Pipe(yaml.Get("contexts"))
if err != nil {
return nil, err
}
if contexts == nil { if contexts == nil {
return nil, errors.New("\"contexts\" entry is nil") return nil, errors.New("\"contexts\" entry is nil")
} else if contexts.Kind != yaml.SequenceNode { } else if contexts.YNode().Kind != yaml.SequenceNode {
return nil, errors.New("\"contexts\" is not a sequence node") return nil, errors.New("\"contexts\" is not a sequence node")
} }
return contexts, nil return contexts, nil
} }
func (k *Kubeconfig) contextNode(name string) (*yaml.Node, error) { func (k *Kubeconfig) contextNode(name string) (*yaml.RNode, error) {
contexts, err := k.contextsNode() context, err := k.config.Pipe(yaml.Lookup("contexts", "[name="+name+"]"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if context == nil {
for _, contextNode := range contexts.Content { return nil, errors.Errorf("context with name \"%s\" not found", name)
nameNode := valueOf(contextNode, "name")
if nameNode.Kind == yaml.ScalarNode && nameNode.Value == name {
return contextNode, nil
}
} }
return nil, errors.Errorf("context with name \"%s\" not found", name) return context, nil
} }
func (k *Kubeconfig) ContextNames() []string { func (k *Kubeconfig) ContextNames() []string {
contexts := valueOf(k.rootNode, "contexts") contexts, err := k.config.Pipe(yaml.Get("contexts"))
if contexts == nil { if err != nil {
return nil return nil
} }
if contexts.Kind != yaml.SequenceNode { names, err := contexts.ElementValues("name")
if err != nil {
return nil return nil
} }
return names
var ctxNames []string
for _, ctx := range contexts.Content {
nameVal := valueOf(ctx, "name")
if nameVal != nil {
ctxNames = append(ctxNames, nameVal.Value)
}
}
return ctxNames
} }
func (k *Kubeconfig) ContextExists(name string) bool { func (k *Kubeconfig) ContextExists(name string) bool {
@ -72,15 +64,3 @@ func (k *Kubeconfig) ContextExists(name string) bool {
} }
return false return false
} }
func valueOf(mapNode *yaml.Node, key string) *yaml.Node {
if mapNode.Kind != yaml.MappingNode {
return nil
}
for i, ch := range mapNode.Content {
if i%2 == 0 && ch.Kind == yaml.ScalarNode && ch.Value == key {
return mapNode.Content[i+1]
}
}
return nil
}

View File

@ -14,18 +14,26 @@
package kubeconfig package kubeconfig
import (
"strings"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// GetCurrentContext returns "current-context" value in given // GetCurrentContext returns "current-context" value in given
// kubeconfig object Node, or returns "" if not found. // kubeconfig object Node, or returns "" if not found.
func (k *Kubeconfig) GetCurrentContext() string { func (k *Kubeconfig) GetCurrentContext() string {
v := valueOf(k.rootNode, "current-context") v, err := k.config.Pipe(yaml.Get("current-context"))
if v == nil { if err != nil {
return "" return ""
} }
return v.Value str, err := v.String()
if err != nil {
return ""
}
return strings.TrimSpace(str)
} }
func (k *Kubeconfig) UnsetCurrentContext() error { func (k *Kubeconfig) UnsetCurrentContext() error {
curCtxValNode := valueOf(k.rootNode, "current-context") return k.config.PipeE(yaml.SetField("current-context", yaml.NewStringRNode("")))
curCtxValNode.Value = ""
return nil
} }

View File

@ -35,8 +35,8 @@ type Loader interface {
type Kubeconfig struct { type Kubeconfig struct {
loader Loader loader Loader
f ReadWriteResetCloser f ReadWriteResetCloser
rootNode *yaml.Node config *yaml.RNode
} }
func (k *Kubeconfig) WithLoader(l Loader) *Kubeconfig { func (k *Kubeconfig) WithLoader(l Loader) *Kubeconfig {
@ -65,15 +65,19 @@ func (k *Kubeconfig) Parse() error {
if err := yaml.NewDecoder(f).Decode(&v); err != nil { if err := yaml.NewDecoder(f).Decode(&v); err != nil {
return errors.Wrap(err, "failed to decode") return errors.Wrap(err, "failed to decode")
} }
k.rootNode = v.Content[0] k.config = yaml.NewRNode(&v)
if k.rootNode.Kind != yaml.MappingNode { if k.config.YNode().Kind != yaml.MappingNode {
return errors.New("kubeconfig file is not a map document") return errors.New("kubeconfig file is not a map document")
} }
return nil return nil
} }
func (k *Kubeconfig) Bytes() ([]byte, error) { func (k *Kubeconfig) Bytes() ([]byte, error) {
return yaml.Marshal(k.rootNode) str, err := k.config.String()
if err != nil {
return nil, err
}
return []byte(str), nil
} }
func (k *Kubeconfig) Save() error { func (k *Kubeconfig) Save() error {
@ -82,5 +86,5 @@ func (k *Kubeconfig) Save() error {
} }
enc := yaml.NewEncoder(k.f) enc := yaml.NewEncoder(k.f)
enc.SetIndent(0) enc.SetIndent(0)
return enc.Encode(k.rootNode) return enc.Encode(k.config.YNode())
} }

View File

@ -14,7 +14,11 @@
package kubeconfig package kubeconfig
import "sigs.k8s.io/kustomize/kyaml/yaml" import (
"strings"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
const ( const (
defaultNamespace = "default" defaultNamespace = "default"
@ -25,53 +29,27 @@ func (k *Kubeconfig) NamespaceOfContext(contextName string) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
ctxBody := valueOf(ctx, "context") namespace, err := ctx.Pipe(yaml.Lookup("context", "namespace"))
if ctxBody == nil { if namespace == nil || err != nil {
return defaultNamespace, nil return defaultNamespace, err
} }
ns := valueOf(ctxBody, "namespace") nsStr, err := namespace.String()
if ns == nil || ns.Value == "" { if nsStr == "" || err != nil {
return defaultNamespace, nil return defaultNamespace, err
} }
return ns.Value, nil return strings.TrimSpace(nsStr), nil
} }
func (k *Kubeconfig) SetNamespace(ctxName string, ns string) error { func (k *Kubeconfig) SetNamespace(ctxName string, ns string) error {
ctxNode, err := k.contextNode(ctxName) ctx, err := k.contextNode(ctxName)
if err != nil { if err != nil {
return err return err
} }
if err := ctx.PipeE(
var ctxBodyNodeWasEmpty bool // actual namespace value is in contexts[index].context.namespace, but .context might not exist yaml.LookupCreate(yaml.MappingNode, "context"),
ctxBodyNode := valueOf(ctxNode, "context") yaml.SetField("namespace", yaml.NewStringRNode(ns)),
if ctxBodyNode == nil { ); err != nil {
ctxBodyNodeWasEmpty = true return err
ctxBodyNode = &yaml.Node{
Kind: yaml.MappingNode,
}
}
nsNode := valueOf(ctxBodyNode, "namespace")
if nsNode != nil {
nsNode.Value = ns
return nil
}
keyNode := &yaml.Node{
Kind: yaml.ScalarNode,
Value: "namespace",
Tag: "!!str"}
valueNode := &yaml.Node{
Kind: yaml.ScalarNode,
Value: ns,
Tag: "!!str"}
ctxBodyNode.Content = append(ctxBodyNode.Content, keyNode, valueNode)
if ctxBodyNodeWasEmpty {
ctxNode.Content = append(ctxNode.Content, &yaml.Node{
Kind: yaml.ScalarNode,
Value: "context",
Tag: "!!str",
}, ctxBodyNode)
} }
return nil return nil
} }