-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e904f61
commit 5dfa929
Showing
6 changed files
with
450 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
// Copyright 2019 The Kubernetes Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package create | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/spf13/cobra" | ||
|
||
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct" | ||
"sigs.k8s.io/kustomize/v3/pkg/commands/kustfile" | ||
"sigs.k8s.io/kustomize/v3/pkg/commands/util" | ||
"sigs.k8s.io/kustomize/v3/pkg/fs" | ||
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig" | ||
) | ||
|
||
type createFlags struct { | ||
resources []string | ||
namespace string | ||
annotations string | ||
labels string | ||
prefix string | ||
suffix string | ||
detectResources bool | ||
detectRecursive bool | ||
path string | ||
} | ||
|
||
// NewCmdCreate returns an instance of 'create' subcommand. | ||
func NewCmdCreate(fSys fs.FileSystem) *cobra.Command { | ||
opts := createFlags{path: "."} | ||
c := &cobra.Command{ | ||
Use: "create", | ||
Short: "Create a new kustomization in the current directory", | ||
Long: "", | ||
Example: ` | ||
# Create a new overlay from the base '../base". | ||
kustomize create --resource ../base | ||
# Create a new kustomization detecting resources in the current directory. | ||
kustomize create --autodetect | ||
# Create a new kustomization with multiple resources and fields set. | ||
kustomize create --resource depoyment.yaml --resource service.yaml --namespace staging --nameprefix acme- | ||
`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
return runCreate(opts, fSys) | ||
}, | ||
} | ||
c.Flags().StringSliceVar( | ||
&opts.resources, | ||
"resource", | ||
[]string{}, | ||
"Name of a file containing a file to add to the kustomization file.") | ||
c.Flags().StringVar( | ||
&opts.namespace, | ||
"namespace", | ||
"", | ||
"Set the value of the namespace field in the customization file.") | ||
c.Flags().StringVar( | ||
&opts.annotations, | ||
"annotation", | ||
"", | ||
"Add one or more common annotations.") | ||
c.Flags().StringVar( | ||
&opts.labels, | ||
"label", | ||
"", | ||
"Add one or more common labels.") | ||
c.Flags().StringVar( | ||
&opts.prefix, | ||
"nameprefix", | ||
"", | ||
"Sets the value of the namePrefix field in the kustomization file.") | ||
c.Flags().StringVar( | ||
&opts.suffix, | ||
"namesuffix", | ||
"", | ||
"Sets the value of the nameSuffix field in the kustomization file.") | ||
c.Flags().BoolVar( | ||
&opts.detectResources, | ||
"autodetect", | ||
false, | ||
"Search for kubernetes resources in the current directory to be added to the kustomization file.") | ||
c.Flags().BoolVar( | ||
&opts.detectRecursive, | ||
"recursive", | ||
false, | ||
"Enable recursive directory searching for resource auto-detection.") | ||
return c | ||
} | ||
|
||
func runCreate(opts createFlags, fSys fs.FileSystem) error { | ||
resources, err := util.GlobPatterns(fSys, opts.resources) | ||
if err != nil { | ||
return err | ||
} | ||
if _, err := kustfile.NewKustomizationFile(fSys); err == nil { | ||
return fmt.Errorf("kustomization file already exists") | ||
} | ||
if opts.detectResources { | ||
detected, err := detectResources(fSys, opts.path, opts.detectRecursive) | ||
if err != nil { | ||
return err | ||
} | ||
for _, resource := range detected { | ||
if kustfile.StringInSlice(resource, resources) { | ||
continue | ||
} | ||
resources = append(resources, resource) | ||
} | ||
} | ||
f, err := fSys.Create("kustomization.yaml") | ||
if err != nil { | ||
return err | ||
} | ||
f.Close() | ||
mf, err := kustfile.NewKustomizationFile(fSys) | ||
if err != nil { | ||
return err | ||
} | ||
m, err := mf.Read() | ||
if err != nil { | ||
return err | ||
} | ||
m.Resources = resources | ||
m.Namespace = opts.namespace | ||
m.NamePrefix = opts.prefix | ||
m.NameSuffix = opts.suffix | ||
annotations, err := util.ConvertToMap(opts.annotations, "annotation") | ||
if err != nil { | ||
return err | ||
} | ||
m.CommonAnnotations = annotations | ||
labels, err := util.ConvertToMap(opts.labels, "label") | ||
if err != nil { | ||
return err | ||
} | ||
m.CommonLabels = labels | ||
return mf.Write(m) | ||
} | ||
|
||
func detectResources(fSys fs.FileSystem, base string, recursive bool) ([]string, error) { | ||
var paths []string | ||
factory := kunstruct.NewKunstructuredFactoryImpl() | ||
err := fSys.Walk(base, func(path string, info os.FileInfo, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
if path == base { | ||
return nil | ||
} | ||
if info.IsDir() { | ||
if !recursive { | ||
return filepath.SkipDir | ||
} | ||
// If a sub-directory contains an existing kustomization file add the | ||
// directory as a resource and do not decend into it. | ||
for _, kfilename := range pgmconfig.KustomizationFileNames { | ||
if fSys.Exists(filepath.Join(path, kfilename)) { | ||
paths = append(paths, path) | ||
return filepath.SkipDir | ||
} | ||
} | ||
return nil | ||
} | ||
fContents, err := fSys.ReadFile(path) | ||
if err != nil { | ||
return err | ||
} | ||
if _, err := factory.SliceFromBytes(fContents); err != nil { | ||
return nil | ||
} | ||
paths = append(paths, path) | ||
return nil | ||
}) | ||
return paths, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
// Copyright 2019 The Kubernetes Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package create | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"sigs.k8s.io/kustomize/v3/pkg/commands/kustfile" | ||
"sigs.k8s.io/kustomize/v3/pkg/fs" | ||
"sigs.k8s.io/kustomize/v3/pkg/types" | ||
) | ||
|
||
func readKustomizationFS(t *testing.T, fakeFS fs.FileSystem) *types.Kustomization { | ||
kf, err := kustfile.NewKustomizationFile(fakeFS) | ||
if err != nil { | ||
t.Errorf("unexpected new error %v", err) | ||
} | ||
m, err := kf.Read() | ||
if err != nil { | ||
t.Errorf("unexpected read error %v", err) | ||
} | ||
return m | ||
} | ||
func TestCreateNoArgs(t *testing.T) { | ||
fakeFS := fs.MakeFakeFS() | ||
cmd := NewCmdCreate(fakeFS) | ||
err := cmd.RunE(cmd, []string{}) | ||
if err != nil { | ||
t.Errorf("unexpected cmd error: %v", err) | ||
} | ||
readKustomizationFS(t, fakeFS) | ||
} | ||
|
||
func TestCreateWithResources(t *testing.T) { | ||
fakeFS := fs.MakeFakeFS() | ||
fakeFS.WriteFile("foo.yaml", []byte("")) | ||
opts := createFlags{resources: []string{"foo.yaml"}} | ||
err := runCreate(opts, fakeFS) | ||
if err != nil { | ||
t.Errorf("unexpected cmd error: %v", err) | ||
} | ||
m := readKustomizationFS(t, fakeFS) | ||
expected := []string{"foo.yaml"} | ||
if !reflect.DeepEqual(m.Resources, expected) { | ||
t.Fatalf("expected %+v but got %+v", expected, m.Resources) | ||
} | ||
} | ||
|
||
func TestCreateWithNamespace(t *testing.T) { | ||
fakeFS := fs.MakeFakeFS() | ||
want := "foo" | ||
opts := createFlags{namespace: want} | ||
err := runCreate(opts, fakeFS) | ||
if err != nil { | ||
t.Errorf("unexpected cmd error: %v", err) | ||
} | ||
m := readKustomizationFS(t, fakeFS) | ||
got := m.Namespace | ||
if got != want { | ||
t.Errorf("want: %s, got: %s", want, got) | ||
} | ||
} | ||
|
||
func TestCreateWithLabels(t *testing.T) { | ||
fakeFS := fs.MakeFakeFS() | ||
opts := createFlags{labels: "foo:bar"} | ||
err := runCreate(opts, fakeFS) | ||
if err != nil { | ||
t.Errorf("unexpected cmd error: %v", err) | ||
} | ||
m := readKustomizationFS(t, fakeFS) | ||
expected := map[string]string{"foo": "bar"} | ||
if !reflect.DeepEqual(m.CommonLabels, expected) { | ||
t.Fatalf("expected %+v but got %+v", expected, m.CommonLabels) | ||
} | ||
} | ||
|
||
func TestCreateWithAnnotations(t *testing.T) { | ||
fakeFS := fs.MakeFakeFS() | ||
opts := createFlags{annotations: "foo:bar"} | ||
err := runCreate(opts, fakeFS) | ||
if err != nil { | ||
t.Errorf("unexpected cmd error: %v", err) | ||
} | ||
m := readKustomizationFS(t, fakeFS) | ||
expected := map[string]string{"foo": "bar"} | ||
if !reflect.DeepEqual(m.CommonAnnotations, expected) { | ||
t.Fatalf("expected %+v but got %+v", expected, m.CommonAnnotations) | ||
} | ||
} | ||
|
||
func TestCreateWithNamePrefix(t *testing.T) { | ||
fakeFS := fs.MakeFakeFS() | ||
want := "foo-" | ||
opts := createFlags{prefix: want} | ||
err := runCreate(opts, fakeFS) | ||
if err != nil { | ||
t.Errorf("unexpected cmd error: %v", err) | ||
} | ||
m := readKustomizationFS(t, fakeFS) | ||
got := m.NamePrefix | ||
if got != want { | ||
t.Errorf("want: %s, got: %s", want, got) | ||
} | ||
} | ||
|
||
func TestCreateWithNameSuffix(t *testing.T) { | ||
fakeFS := fs.MakeFakeFS() | ||
opts := createFlags{suffix: "-foo"} | ||
err := runCreate(opts, fakeFS) | ||
if err != nil { | ||
t.Errorf("unexpected cmd error: %v", err) | ||
} | ||
m := readKustomizationFS(t, fakeFS) | ||
if m.NameSuffix != "-foo" { | ||
t.Errorf("want: -foo, got: %s", m.NameSuffix) | ||
} | ||
} | ||
|
||
func writeDetectContent(fakeFS fs.FileSystem) { | ||
fakeFS.WriteFile("/test.yaml", []byte(` | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: test`)) | ||
fakeFS.WriteFile("/README.md", []byte(` | ||
# Not a k8s resource | ||
This file is not a valid kubernetes object.`)) | ||
fakeFS.Mkdir("/sub") | ||
fakeFS.WriteFile("/sub/test.yaml", []byte(` | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: test2`)) | ||
fakeFS.WriteFile("/sub/README.md", []byte(` | ||
# Not a k8s resource | ||
This file in a subdirectory is not a valid kubernetes object.`)) | ||
fakeFS.Mkdir("/overlay") | ||
fakeFS.WriteFile("/overlay/test.yaml", []byte(` | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: test3`)) | ||
fakeFS.WriteFile("/overlay/kustomization.yaml", []byte(` | ||
resources: | ||
- test.yaml`)) | ||
} | ||
|
||
func TestCreateWithDetect(t *testing.T) { | ||
fakeFS := fs.MakeFakeFS() | ||
writeDetectContent(fakeFS) | ||
opts := createFlags{path: "/", detectResources: true} | ||
err := runCreate(opts, fakeFS) | ||
if err != nil { | ||
t.Fatalf("unexpected cmd error: %v", err) | ||
} | ||
m := readKustomizationFS(t, fakeFS) | ||
expected := []string{"/test.yaml"} | ||
if !reflect.DeepEqual(m.Resources, expected) { | ||
t.Fatalf("expected %+v but got %+v", expected, m.Resources) | ||
} | ||
} | ||
|
||
func TestCreateWithDetectRecursive(t *testing.T) { | ||
fakeFS := fs.MakeFakeFS() | ||
writeDetectContent(fakeFS) | ||
opts := createFlags{path: "/", detectResources: true, detectRecursive: true} | ||
err := runCreate(opts, fakeFS) | ||
if err != nil { | ||
t.Fatalf("unexpected cmd error: %v", err) | ||
} | ||
m := readKustomizationFS(t, fakeFS) | ||
expected := []string{"/overlay", "/sub/test.yaml", "/test.yaml"} | ||
if !reflect.DeepEqual(m.Resources, expected) { | ||
t.Fatalf("expected %+v but got %+v", expected, m.Resources) | ||
} | ||
} |
Oops, something went wrong.