Files
kustomize/cmd/config/internal/commands/annotate.go
2021-07-24 09:18:58 -07:00

149 lines
3.8 KiB
Go

// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package commands
import (
"fmt"
"io"
"strings"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// NewAnnotateRunner returns a command runner.
func NewAnnotateRunner(parent string) *AnnotateRunner {
r := &AnnotateRunner{}
c := &cobra.Command{
Use: "annotate [DIR]",
Args: cobra.MaximumNArgs(1),
Short: commands.AnnotateShort,
Long: commands.AnnotateLong,
Example: commands.AnnotateExamples,
RunE: r.runE,
Deprecated: "use the `commonAnnotations` field in your kustomization file.",
}
runner.FixDocs(parent, c)
r.Command = c
c.Flags().StringVar(&r.Kind, "kind", "", "Resource kind to annotate")
c.Flags().StringVar(&r.ApiVersion, "apiVersion", "", "Resource apiVersion to annotate")
c.Flags().StringVar(&r.Name, "name", "", "Resource name to annotate")
c.Flags().StringVar(&r.Namespace, "namespace", "", "Resource namespace to annotate")
c.Flags().StringSliceVar(&r.Values, "kv", []string{}, "annotation as KEY=VALUE")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"add annotations recursively in all the nested subpackages")
return r
}
func AnnotateCommand(parent string) *cobra.Command {
return NewAnnotateRunner(parent).Command
}
type AnnotateRunner struct {
Command *cobra.Command
Values []string
Kind string
Name string
ApiVersion string
Namespace string
Path string
RecurseSubPackages bool
}
func (r *AnnotateRunner) runE(c *cobra.Command, args []string) error {
var input []kio.Reader
var output []kio.Writer
if len(args) == 0 {
rw := &kio.ByteReadWriter{Reader: c.InOrStdin(), Writer: c.OutOrStdout()}
input = []kio.Reader{rw}
output = []kio.Writer{rw}
return runner.HandleError(c, kio.Pipeline{
Inputs: input,
Filters: []kio.Filter{r},
Outputs: output,
}.Execute())
}
e := runner.ExecuteCmdOnPkgs{
Writer: c.OutOrStdout(),
NeedOpenAPI: false,
RecurseSubPackages: r.RecurseSubPackages,
CmdRunner: r,
RootPkgPath: args[0],
}
err := e.Execute()
if err != nil {
return err
}
return nil
}
func (r *AnnotateRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
rw := &kio.LocalPackageReadWriter{
PackagePath: pkgPath,
NoDeleteFiles: true,
PackageFileName: ext.KRMFileName(),
}
input := []kio.Reader{rw}
output := []kio.Writer{rw}
err := kio.Pipeline{
Inputs: input,
Filters: []kio.Filter{r},
Outputs: output,
}.Execute()
if err != nil {
// return err if there is only package
if !r.RecurseSubPackages {
return err
}
// print error message and continue if there are multiple packages to annotate
_, _ = fmt.Fprintf(w, "%s\n", err.Error())
} else {
_, _ = fmt.Fprint(w, "added annotations in the package\n")
}
return nil
}
func (r *AnnotateRunner) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
for i := range nodes {
n := nodes[i]
m, err := n.GetMeta()
if err != nil {
return nil, err
}
if r.Kind != "" && r.Kind != m.Kind {
continue
}
if r.ApiVersion != "" && r.ApiVersion != m.APIVersion {
continue
}
if r.Namespace != "" && r.Namespace != m.Namespace {
continue
}
if r.Name != "" && r.Name != m.Name {
continue
}
for i := range r.Values {
// split key, value pairs
kv := strings.SplitN(r.Values[i], "=", 2)
if len(kv) != 2 {
return nil, errors.Errorf("must specify --kv as KEY=VALUE: %s", r.Values[i])
}
if err := n.PipeE(yaml.SetAnnotation(kv[0], kv[1])); err != nil {
return nil, err
}
}
}
return nodes, nil
}