// Copyright 2019 The Kubernetes Authors. // SPDX-License-Identifier: Apache-2.0 package runfn import ( "io" "path/filepath" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/yaml" ) // RunFns runs the set of configuration functions in a local directory against // the Resources in that directory type RunFns struct { StorageMounts []filters.StorageMount // Path is the path to the directory containing functions Path string // FunctionPaths Paths allows functions to be specified outside the configuration // directory FunctionPaths []string // Output can be set to write the result to Output rather than back to the directory Output io.Writer // containerFilterProvider may be override by tests to fake invoking containers containerFilterProvider func(string, string, *yaml.RNode) kio.Filter } // Execute runs the command func (r RunFns) Execute() error { // make the path absolute so it works on mac var err error r.Path, err = filepath.Abs(r.Path) if err != nil { return errors.Wrap(err) } // default the containerFilterProvider if it hasn't been override. Split out for testing. (&r).init() // identify the configuration functions in the directory buff := &kio.PackageBuffer{} err = kio.Pipeline{ Inputs: []kio.Reader{kio.LocalPackageReader{PackagePath: r.Path}}, Filters: []kio.Filter{&filters.IsReconcilerFilter{}}, Outputs: []kio.Writer{buff}, }.Execute() if err != nil { return err } for i := range r.FunctionPaths { err := kio.Pipeline{ Inputs: []kio.Reader{kio.LocalPackageReader{PackagePath: r.FunctionPaths[i]}}, Outputs: []kio.Writer{buff}, }.Execute() if err != nil { return err } } // reconcile each local API var fltrs []kio.Filter for i := range buff.Nodes { api := buff.Nodes[i] img, path := filters.GetContainerName(api) fltrs = append(fltrs, r.containerFilterProvider(img, path, api)) } pkgIO := &kio.LocalPackageReadWriter{PackagePath: r.Path} inputs := []kio.Reader{pkgIO} var outputs []kio.Writer if r.Output == nil { // write back to the package outputs = append(outputs, pkgIO) } else { // write to the output instead of the directory outputs = append(outputs, kio.ByteWriter{Writer: r.Output}) } return kio.Pipeline{Inputs: inputs, Filters: fltrs, Outputs: outputs}.Execute() } // init initializes the RunFns with a containerFilterProvider. func (r *RunFns) init() { // if containerFilterProvider hasn't been set, use the default if r.containerFilterProvider == nil { r.containerFilterProvider = func(image, path string, api *yaml.RNode) kio.Filter { cf := &filters.ContainerFilter{Image: image, Config: api, StorageMounts: r.StorageMounts} return cf } } }