mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-10 08:20:59 +00:00
Namereference handler needs to address simulatenous change of name and namespace in ClusterRoleBinding for instance.
239 lines
5.9 KiB
Go
239 lines
5.9 KiB
Go
// Copyright 2019 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package build
|
|
|
|
import (
|
|
"io"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
"sigs.k8s.io/kustomize/v3/pkg/fs"
|
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
|
"sigs.k8s.io/kustomize/v3/pkg/loader"
|
|
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig"
|
|
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
|
"sigs.k8s.io/kustomize/v3/pkg/target"
|
|
"sigs.k8s.io/kustomize/v3/plugin/builtin"
|
|
"sigs.k8s.io/yaml"
|
|
)
|
|
|
|
// Options contain the options for running a build
|
|
type Options struct {
|
|
kustomizationPath string
|
|
outputPath string
|
|
loadRestrictor loader.LoadRestrictorFunc
|
|
outOrder reorderOutput
|
|
}
|
|
|
|
// NewOptions creates a Options object
|
|
func NewOptions(p, o string) *Options {
|
|
return &Options{
|
|
kustomizationPath: p,
|
|
outputPath: o,
|
|
loadRestrictor: loader.RestrictionRootOnly,
|
|
}
|
|
}
|
|
|
|
var examples = `
|
|
To generate the resources specified in 'someDir/kustomization.yaml', run
|
|
|
|
kustomize build someDir
|
|
|
|
The default argument to 'build' is '.' (the current working directory).
|
|
|
|
The argument can be a URL resolving to a directory
|
|
with a kustomization.yaml file, e.g.
|
|
|
|
kustomize build \
|
|
github.com/kubernetes-sigs/kustomize//examples/multibases/dev/?ref=v1.0.6
|
|
|
|
The URL should be formulated as described at
|
|
https://github.com/hashicorp/go-getter#url-format
|
|
`
|
|
|
|
// NewCmdBuild creates a new build command.
|
|
func NewCmdBuild(
|
|
out io.Writer, fSys fs.FileSystem,
|
|
v ifc.Validator, rf *resmap.Factory,
|
|
ptf resmap.PatchFactory) *cobra.Command {
|
|
var o Options
|
|
|
|
pluginConfig := plugins.DefaultPluginConfig()
|
|
pl := plugins.NewLoader(pluginConfig, rf)
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "build {path}",
|
|
Short: "Print configuration per contents of " + pgmconfig.KustomizationFileNames[0],
|
|
Example: examples,
|
|
SilenceUsage: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
err := o.Validate(args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return o.RunBuild(out, v, fSys, rf, ptf, pl)
|
|
},
|
|
}
|
|
|
|
cmd.Flags().StringVarP(
|
|
&o.outputPath,
|
|
"output", "o", "",
|
|
"If specified, write the build output to this path.")
|
|
loader.AddFlagLoadRestrictor(cmd.Flags())
|
|
plugins.AddFlagEnablePlugins(
|
|
cmd.Flags(), &pluginConfig.Enabled)
|
|
addFlagReorderOutput(cmd.Flags())
|
|
cmd.AddCommand(NewCmdBuildPrune(out, v, fSys, rf, ptf, pl))
|
|
return cmd
|
|
}
|
|
|
|
// Validate validates build command.
|
|
func (o *Options) Validate(args []string) (err error) {
|
|
if len(args) > 1 {
|
|
return errors.New(
|
|
"specify one path to " + pgmconfig.KustomizationFileNames[0])
|
|
}
|
|
if len(args) == 0 {
|
|
o.kustomizationPath = loader.CWD
|
|
} else {
|
|
o.kustomizationPath = args[0]
|
|
}
|
|
o.loadRestrictor, err = loader.ValidateFlagLoadRestrictor()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
o.outOrder, err = validateFlagReorderOutput()
|
|
return
|
|
}
|
|
|
|
// RunBuild runs build command.
|
|
func (o *Options) RunBuild(
|
|
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
|
rf *resmap.Factory, ptf resmap.PatchFactory,
|
|
pl *plugins.Loader) error {
|
|
ldr, err := loader.NewLoader(
|
|
o.loadRestrictor, v, o.kustomizationPath, fSys)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer ldr.Cleanup()
|
|
kt, err := target.NewKustTarget(ldr, rf, ptf, pl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m, err := kt.MakeCustomizedResMap()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return o.emitResources(out, fSys, m)
|
|
}
|
|
|
|
func (o *Options) RunBuildPrune(
|
|
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
|
rf *resmap.Factory, ptf resmap.PatchFactory,
|
|
pl *plugins.Loader) error {
|
|
ldr, err := loader.NewLoader(
|
|
o.loadRestrictor, v, o.kustomizationPath, fSys)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer ldr.Cleanup()
|
|
kt, err := target.NewKustTarget(ldr, rf, ptf, pl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m, err := kt.MakePruneConfigMap()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return o.emitResources(out, fSys, m)
|
|
}
|
|
|
|
func (o *Options) emitResources(
|
|
out io.Writer, fSys fs.FileSystem, m resmap.ResMap) error {
|
|
if o.outputPath != "" && fSys.IsDir(o.outputPath) {
|
|
return writeIndividualFiles(fSys, o.outputPath, m)
|
|
}
|
|
if o.outOrder == legacy {
|
|
// Done this way just to show how overall sorting
|
|
// can be performed by a plugin. This particular
|
|
// plugin doesn't require configuration; just make
|
|
// it and call transform.
|
|
builtin.NewLegacyOrderTransformerPlugin().Transform(m)
|
|
}
|
|
res, err := m.AsYaml()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if o.outputPath != "" {
|
|
return fSys.WriteFile(o.outputPath, res)
|
|
}
|
|
_, err = out.Write(res)
|
|
return err
|
|
}
|
|
|
|
func NewCmdBuildPrune(
|
|
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
|
rf *resmap.Factory, ptf resmap.PatchFactory,
|
|
pl *plugins.Loader) *cobra.Command {
|
|
var o Options
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "alpha-inventory [path]",
|
|
Short: "Print the inventory object which contains a list of all other objects",
|
|
Example: examples,
|
|
SilenceUsage: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
err := o.Validate(args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return o.RunBuildPrune(out, v, fSys, rf, ptf, pl)
|
|
},
|
|
}
|
|
return cmd
|
|
}
|
|
|
|
func writeIndividualFiles(
|
|
fSys fs.FileSystem, folderPath string, m resmap.ResMap) error {
|
|
byNamespace := m.GroupedByCurrentNamespace()
|
|
for namespace, resList := range byNamespace {
|
|
for _, res := range resList {
|
|
fName := fileName(res)
|
|
if len(byNamespace) > 1 {
|
|
fName = strings.ToLower(namespace) + "_" + fName
|
|
}
|
|
err := writeFile(fSys, folderPath, fName, res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
for _, res := range m.NonNamespaceable() {
|
|
err := writeFile(fSys, folderPath, fileName(res), res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func fileName(res *resource.Resource) string {
|
|
return strings.ToLower(res.GetGvk().String()) +
|
|
"_" + strings.ToLower(res.GetName()) + ".yaml"
|
|
}
|
|
|
|
func writeFile(
|
|
fSys fs.FileSystem, path, fName string, res *resource.Resource) error {
|
|
out, err := yaml.Marshal(res.Map())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return fSys.WriteFile(filepath.Join(path, fName), out)
|
|
}
|