Files
kustomize/cmd/config/internal/commands/run-fns.go
Jeff Regan f864e15c68 Merge pull request #2974 from Shell32-Natsu/function-definition
remove not used args & use const string instead of literal
2020-09-15 14:34:25 -07:00

324 lines
8.9 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/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
"sigs.k8s.io/kustomize/kyaml/runfn"
"sigs.k8s.io/kustomize/kyaml/yaml"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
)
// GetCatRunner returns a RunFnRunner.
func GetRunFnRunner(name string) *RunFnRunner {
r := &RunFnRunner{}
c := &cobra.Command{
Use: "run [DIR]",
Short: commands.RunFnsShort,
Long: commands.RunFnsLong,
Example: commands.RunFnsExamples,
RunE: r.runE,
PreRunE: r.preRunE,
}
fixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.")
r.Command = c
r.Command.Flags().BoolVar(
&r.DryRun, "dry-run", false, "print results to stdout")
r.Command.Flags().BoolVar(
&r.GlobalScope, "global-scope", false, "set global scope for functions.")
r.Command.Flags().StringSliceVar(
&r.FnPaths, "fn-path", []string{},
"read functions from these directories instead of the configuration directory.")
r.Command.Flags().StringVar(
&r.Image, "image", "",
"run this image as a function instead of discovering them.")
// NOTE: exec plugins execute arbitrary code -- never change the default value of this flag!!!
r.Command.Flags().BoolVar(
&r.EnableExec, "enable-exec", false /*do not change!*/, "enable support for exec functions -- note: exec functions run arbitrary code -- do not use for untrusted configs!!! (Alpha)")
r.Command.Flags().StringVar(
&r.ExecPath, "exec-path", "", "run an executable as a function. (Alpha)")
r.Command.Flags().BoolVar(
&r.EnableStar, "enable-star", false, "enable support for starlark functions. (Alpha)")
r.Command.Flags().StringVar(
&r.StarPath, "star-path", "", "run a starlark script as a function. (Alpha)")
r.Command.Flags().StringVar(
&r.StarURL, "star-url", "", "run a starlark script as a function. (Alpha)")
r.Command.Flags().StringVar(
&r.StarName, "star-name", "", "name of starlark program. (Alpha)")
r.Command.Flags().StringVar(
&r.ResultsDir, "results-dir", "", "write function results to this dir")
r.Command.Flags().BoolVar(
&r.Network, "network", false, "enable network access for functions that declare it")
r.Command.Flags().StringVar(
&r.NetworkName, "network-name", "bridge", "the docker network to run the container in")
r.Command.Flags().StringArrayVar(
&r.Mounts, "mount", []string{},
"a list of storage options read from the filesystem")
r.Command.Flags().BoolVar(
&r.LogSteps, "log-steps", false, "log steps to stderr")
r.Command.Flags().StringArrayVarP(
&r.Env, "env", "e", []string{},
"a list of environment variables to be used by functions")
return r
}
func RunCommand(name string) *cobra.Command {
return GetRunFnRunner(name).Command
}
// RunFnRunner contains the run function
type RunFnRunner struct {
IncludeSubpackages bool
Command *cobra.Command
DryRun bool
GlobalScope bool
FnPaths []string
Image string
EnableStar bool
StarPath string
StarURL string
StarName string
EnableExec bool
ExecPath string
RunFns runfn.RunFns
ResultsDir string
Network bool
NetworkName string
Mounts []string
LogSteps bool
Env []string
}
func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.RunFns.Execute())
}
// getContainerFunctions parses the commandline flags and arguments into explicit
// Functions to run.
func (r *RunFnRunner) getContainerFunctions(c *cobra.Command, dataItems []string) (
[]*yaml.RNode, error) {
if r.Image == "" && r.StarPath == "" && r.ExecPath == "" && r.StarURL == "" {
return nil, nil
}
var fn *yaml.RNode
var err error
if r.Image != "" {
// create the function spec to set as an annotation
fn, err = yaml.Parse(`container: {}`)
if err != nil {
return nil, err
}
// TODO: add support network, volumes, etc based on flag values
err = fn.PipeE(
yaml.Lookup("container"),
yaml.SetField("image", yaml.NewScalarRNode(r.Image)))
if err != nil {
return nil, err
}
if r.Network {
err = fn.PipeE(
yaml.LookupCreate(yaml.MappingNode, "container", "network"),
yaml.SetField("required", yaml.NewScalarRNode("true")))
if err != nil {
return nil, err
}
}
} else if r.EnableStar && (r.StarPath != "" || r.StarURL != "") {
// create the function spec to set as an annotation
fn, err = yaml.Parse(`starlark: {}`)
if err != nil {
return nil, err
}
if r.StarPath != "" {
err = fn.PipeE(
yaml.Lookup("starlark"),
yaml.SetField("path", yaml.NewScalarRNode(r.StarPath)))
if err != nil {
return nil, err
}
}
if r.StarURL != "" {
err = fn.PipeE(
yaml.Lookup("starlark"),
yaml.SetField("url", yaml.NewScalarRNode(r.StarURL)))
if err != nil {
return nil, err
}
}
err = fn.PipeE(
yaml.Lookup("starlark"),
yaml.SetField("name", yaml.NewScalarRNode(r.StarName)))
if err != nil {
return nil, err
}
} else if r.EnableExec && r.ExecPath != "" {
// create the function spec to set as an annotation
fn, err = yaml.Parse(`exec: {}`)
if err != nil {
return nil, err
}
err = fn.PipeE(
yaml.Lookup("exec"),
yaml.SetField("path", yaml.NewScalarRNode(r.ExecPath)))
if err != nil {
return nil, err
}
}
// create the function config
rc, err := yaml.Parse(`
metadata:
name: function-input
data: {}
`)
if err != nil {
return nil, err
}
// set the function annotation on the function config so it
// is parsed by RunFns
value, err := fn.String()
if err != nil {
return nil, err
}
err = rc.PipeE(
yaml.LookupCreate(yaml.MappingNode, "metadata", "annotations"),
yaml.SetField(runtimeutil.FunctionAnnotationKey, yaml.NewScalarRNode(value)))
if err != nil {
return nil, err
}
// default the function config kind to ConfigMap, this may be overridden
var kind = "ConfigMap"
var version = "v1"
// populate the function config with data. this is a convention for functions
// to be more commandline friendly
if len(dataItems) > 0 {
dataField, err := rc.Pipe(yaml.Lookup("data"))
if err != nil {
return nil, err
}
for i, s := range dataItems {
kv := strings.SplitN(s, "=", 2)
if i == 0 && len(kv) == 1 {
// first argument may be the kind
kind = s
continue
}
if len(kv) != 2 {
return nil, fmt.Errorf("args must have keys and values separated by =")
}
err := dataField.PipeE(yaml.SetField(kv[0], yaml.NewScalarRNode(kv[1])))
if err != nil {
return nil, err
}
}
}
err = rc.PipeE(yaml.SetField("kind", yaml.NewScalarRNode(kind)))
if err != nil {
return nil, err
}
err = rc.PipeE(yaml.SetField("apiVersion", yaml.NewScalarRNode(version)))
if err != nil {
return nil, err
}
return []*yaml.RNode{rc}, nil
}
func toStorageMounts(mounts []string) []runtimeutil.StorageMount {
var sms []runtimeutil.StorageMount
for _, mount := range mounts {
sms = append(sms, runtimeutil.StringToStorageMount(mount))
}
return sms
}
func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
if !r.EnableStar && (r.StarPath != "" || r.StarURL != "") {
return errors.Errorf("must specify --enable-star with --star-path and --star-url")
}
if !r.EnableExec && r.ExecPath != "" {
return errors.Errorf("must specify --enable-exec with --exec-path")
}
if c.ArgsLenAtDash() >= 0 && r.Image == "" &&
!(r.EnableStar && (r.StarPath != "" || r.StarURL != "")) && !(r.EnableExec && r.ExecPath != "") {
return errors.Errorf("must specify --image")
}
var dataItems []string
if c.ArgsLenAtDash() >= 0 {
dataItems = args[c.ArgsLenAtDash():]
args = args[:c.ArgsLenAtDash()]
}
if len(args) > 1 {
return errors.Errorf("0 or 1 arguments supported, function arguments go after '--'")
}
fns, err := r.getContainerFunctions(c, dataItems)
if err != nil {
return err
}
// set the output to stdout if in dry-run mode or no arguments are specified
var output io.Writer
var input io.Reader
if len(args) == 0 {
output = c.OutOrStdout()
input = c.InOrStdin()
} else if r.DryRun {
output = c.OutOrStdout()
}
// set the path if specified as an argument
var path string
if len(args) == 1 {
// argument is the directory
path = args[0]
}
// parse mounts to set storageMounts
storageMounts := toStorageMounts(r.Mounts)
r.RunFns = runfn.RunFns{
FunctionPaths: r.FnPaths,
GlobalScope: r.GlobalScope,
Functions: fns,
Output: output,
Input: input,
Path: path,
Network: r.Network,
NetworkName: r.NetworkName,
EnableStarlark: r.EnableStar,
EnableExec: r.EnableExec,
StorageMounts: storageMounts,
ResultsDir: r.ResultsDir,
LogSteps: r.LogSteps,
Env: r.Env,
}
// don't consider args for the function
return nil
}