diff --git a/pkg/app/application.go b/pkg/app/application.go index a01573b01..32e7d052d 100644 --- a/pkg/app/application.go +++ b/pkg/app/application.go @@ -86,20 +86,6 @@ func (a *Application) MakeCustomizedResMap() (resmap.ResMap, error) { return a.resolveRefsToGeneratedResources(m) } -// MakeUncustomizedResMap purports to create a ResMap without customization. -// The Resources in the returned ResMap include all resources mentioned -// in the kustomization file and transitively reachable via its Bases, -// and all generated secrets and configMaps. -// Meant for use in generating a diff against customized resources. -// TODO: See https://github.com/kubernetes-sigs/kustomize/issues/85 -func (a *Application) MakeUncustomizedResMap() (resmap.ResMap, error) { - m, err := a.loadResMapFromBasesAndResources() - if err != nil { - return nil, err - } - return a.resolveRefsToGeneratedResources(m) -} - // resolveRefsToGeneratedResources fixes all name references. func (a *Application) resolveRefsToGeneratedResources(m resmap.ResMap) (resmap.ResMap, error) { err := transformers.NewNameHashTransformer().Transform(m) diff --git a/pkg/app/application_test.go b/pkg/app/application_test.go index 04535ff51..94724a2aa 100644 --- a/pkg/app/application_test.go +++ b/pkg/app/application_test.go @@ -96,7 +96,6 @@ var deploy = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deploy var cmap = schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"} var secret = schema.GroupVersionKind{Version: "v1", Kind: "Secret"} var ns = schema.GroupVersionKind{Version: "v1", Kind: "Namespace"} -var svc = schema.GroupVersionKind{Version: "v1", Kind: "Service"} func TestResources1(t *testing.T) { expected := resmap.ResMap{ @@ -227,153 +226,6 @@ func TestResourceNotFound(t *testing.T) { } } -func TestRawResources1(t *testing.T) { - expected := resmap.ResMap{ - resource.NewResId(deploy, "dply1"): resource.NewResourceFromMap( - map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "dply1", - }, - }), - resource.NewResId(ns, "ns1"): resource.NewResourceFromMap( - map[string]interface{}{ - "apiVersion": "v1", - "kind": "Namespace", - "metadata": map[string]interface{}{ - "name": "ns1", - }, - }), - } - l := makeLoader1(t) - app, err := NewApplication(l, fs.MakeFakeFS()) - if err != nil { - t.Fatalf("Unexpected construction error %v", err) - } - actual, err := app.MakeUncustomizedResMap() - if err != nil { - t.Fatalf("Unexpected RawResources error %v", err) - } - - if err := expected.ErrorIfNotEqual(actual); err != nil { - t.Fatalf("unexpected inequality: %v", err) - } -} - -const ( - kustomizationContentBase = ` -namePrefix: foo- -commonLabels: - app: banana -resources: - - deployment.yaml -` - kustomizationContentOverlay = ` -commonLabels: - env: staging -resources: - - service.yaml -bases: - - base -` - serviceContent = `apiVersion: v1 -kind: Service -metadata: - name: svc -spec: - type: LoadBalancer -` -) - -func makeLoader2(t *testing.T) loader.Loader { - ldr := loadertest.NewFakeLoader("/testpath") - err := ldr.AddFile("/testpath/"+constants.KustomizationFileName, []byte(kustomizationContentOverlay)) - if err != nil { - t.Fatal(err) - } - err = ldr.AddFile("/testpath/service.yaml", []byte(serviceContent)) - if err != nil { - t.Fatalf("Failed to setup fake ldr.") - } - err = ldr.AddDirectory("/testpath/base") - if err != nil { - t.Fatalf("Failed to setup fake ldr.") - } - err = ldr.AddFile("/testpath/base/"+constants.KustomizationFileName, []byte(kustomizationContentBase)) - if err != nil { - t.Fatalf("Failed to setup fake ldr.") - } - err = ldr.AddFile("/testpath/base/deployment.yaml", []byte(deploymentContent)) - if err != nil { - t.Fatalf("Failed to setup fake ldr.") - } - return ldr -} - -// TODO: This test covers incorrect behavior; it should not pass. -// It asks for raw resources. The Service resource is returned in raw form, -// but the resources in the base are modified to have the banana label, -// the 'foo' name prefix, etc. This method exists only to support the -// diff command comparing customized to non-customized resources; -// perhaps it's not worth supporting the command. -func TestRawResources2(t *testing.T) { - expected := resmap.ResMap{ - resource.NewResIdWithPrefix(deploy, "dply1", "foo-"): resource.NewResourceFromMap( - map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "foo-dply1", - "labels": map[string]interface{}{ - "app": "banana", - }, - }, - "spec": map[string]interface{}{ - "selector": map[string]interface{}{ - "matchLabels": map[string]interface{}{ - "app": "banana", - }, - }, - "template": map[string]interface{}{ - "metadata": map[string]interface{}{ - "labels": map[string]interface{}{ - "app": "banana", - }, - }, - }, - }, - }), - resource.NewResId(svc, "svc"): resource.NewResourceFromMap( - map[string]interface{}{ - "apiVersion": "v1", - "kind": "Service", - "metadata": map[string]interface{}{ - "name": "svc", - }, - "spec": map[string]interface{}{ - "type": "LoadBalancer", - }, - }), - } - l := makeLoader2(t) - app, err := NewApplication(l, fs.MakeFakeFS()) - if err != nil { - t.Fatalf("Unexpected construction error %v", err) - } - actual, err := app.MakeUncustomizedResMap() - if err != nil { - t.Fatalf("Unexpected RawResources error %v", err) - } - - if err := expected.ErrorIfNotEqual(actual); err != nil { - t.Fatalf("unexpected inequality: %v", err) - } - if !loadertest.CleanupCalled { - t.Fatalf("Cleanup should be called") - } -} - func TestSecretTimeout(t *testing.T) { l := loadertest.NewFakeLoader("/testpath") err := l.AddFile("/testpath/"+constants.KustomizationFileName, []byte(kustomizationContent2)) diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 20e987a66..d75d34c38 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -28,7 +28,7 @@ import ( // NewDefaultCommand returns the default (aka root) command for kustomize command. func NewDefaultCommand() *cobra.Command { fsys := fs.MakeRealFS() - stdOut, stdErr := os.Stdout, os.Stderr + stdOut := os.Stdout c := &cobra.Command{ Use: "kustomize", @@ -43,7 +43,6 @@ See https://github.com/kubernetes-sigs/kustomize c.AddCommand( // TODO: Make consistent API for newCmd* functions. newCmdBuild(stdOut, fsys), - newCmdDiff(stdOut, stdErr, fsys), newCmdEdit(fsys), newCmdVersion(stdOut), ) diff --git a/pkg/commands/diff.go b/pkg/commands/diff.go deleted file mode 100644 index 70f3a7c2e..000000000 --- a/pkg/commands/diff.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package commands - -import ( - "errors" - "io" - - "github.com/spf13/cobra" - - "github.com/kubernetes-sigs/kustomize/pkg/app" - "github.com/kubernetes-sigs/kustomize/pkg/constants" - "github.com/kubernetes-sigs/kustomize/pkg/diff" - "github.com/kubernetes-sigs/kustomize/pkg/fs" - "github.com/kubernetes-sigs/kustomize/pkg/loader" -) - -type diffOptions struct { - kustomizationPath string -} - -// newCmdDiff makes the diff command. -func newCmdDiff(out, errOut io.Writer, fs fs.FileSystem) *cobra.Command { - var o diffOptions - - cmd := &cobra.Command{ - Use: "diff [path]", - Short: "diff between customized resources and uncustomized resources", - RunE: func(cmd *cobra.Command, args []string) error { - err := o.Validate(args) - if err != nil { - return err - } - return o.RunDiff(out, errOut, fs) - }, - } - return cmd -} - -// Validate validates diff command. -func (o *diffOptions) Validate(args []string) error { - if len(args) > 1 { - return errors.New("specify one path to " + constants.KustomizationFileName) - } - if len(args) == 0 { - o.kustomizationPath = "./" - return nil - } - o.kustomizationPath = args[0] - return nil -} - -// RunDiff gets the differences between Application.MakeCustomizedResMap() and Application.MakeUncustomizedResMap(). -func (o *diffOptions) RunDiff(out, errOut io.Writer, fSys fs.FileSystem) error { - - rootLoader, err := loader.NewLoader(o.kustomizationPath, "", fSys) - if err != nil { - return err - } - defer rootLoader.Cleanup() - - application, err := app.NewApplication(rootLoader, fSys) - if err != nil { - return err - } - transformedResources, err := application.MakeCustomizedResMap() - if err != nil { - return err - } - rawResources, err := application.MakeUncustomizedResMap() - if err != nil { - return err - } - - return diff.RunDiff(rawResources, transformedResources, out, errOut) -} diff --git a/pkg/commands/diff_test.go b/pkg/commands/diff_test.go deleted file mode 100644 index 31d10a992..000000000 --- a/pkg/commands/diff_test.go +++ /dev/null @@ -1,131 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package commands - -import ( - "bytes" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "regexp" - "strings" - "testing" - - "github.com/ghodss/yaml" - - "github.com/kubernetes-sigs/kustomize/pkg/fs" - "k8s.io/apimachinery/pkg/util/sets" -) - -type DiffTestCase struct { - Description string `yaml:"description"` - Args []string `yaml:"args"` - Filename string `yaml:"filename"` - // path to the file that contains the expected output - ExpectedDiff string `yaml:"expectedDiff"` - ExpectedError string `yaml:"expectedError"` -} - -func TestDiff(t *testing.T) { - const updateEnvVar = "UPDATE_KUSTOMIZE_EXPECTED_DATA" - updateKustomizeExpected := os.Getenv(updateEnvVar) == "true" - - tempDir := regexp.QuoteMeta(filepath.Clean(os.TempDir())) - noopDir, _ := regexp.Compile(tempDir + `/noop-[0-9]*/`) - transformedDir, _ := regexp.Compile(tempDir + `/transformed-[0-9]*/`) - timestamp, _ := regexp.Compile(`[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9].[0-9]* [+-]{1}[0-9]{4}`) - - fSys := fs.MakeRealFS() - - testcases := sets.NewString() - filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if path == "testdata" { - return nil - } - name := filepath.Base(path) - if info.IsDir() { - if strings.HasPrefix(name, "testcase-") { - testcases.Insert(strings.TrimPrefix(name, "testcase-")) - } - return filepath.SkipDir - } - return nil - }) - // sanity check that we found the right folder - if !testcases.Has("simple") { - t.Fatalf("Error locating testcases") - } - - for _, testcaseName := range testcases.List() { - t.Run(testcaseName, func(t *testing.T) { - runDiffTestCase(t, testcaseName, updateKustomizeExpected, fSys, - noopDir, transformedDir, timestamp) - }) - } -} - -func runDiffTestCase(t *testing.T, testcaseName string, updateKustomizeExpected bool, fs fs.FileSystem, - noopDir, transformedDir, timestamp *regexp.Regexp) { - name := testcaseName - testcase := DiffTestCase{} - testcaseDir := filepath.Join("testdata", "testcase-"+name) - testcaseData, err := ioutil.ReadFile(filepath.Join(testcaseDir, "test.yaml")) - if err != nil { - t.Fatalf("%s: %v", name, err) - } - if err := yaml.Unmarshal(testcaseData, &testcase); err != nil { - t.Fatalf("%s: %v", name, err) - } - - diffOps := &diffOptions{ - kustomizationPath: testcase.Filename, - } - buf := bytes.NewBuffer([]byte{}) - err = diffOps.RunDiff(buf, os.Stderr, fs) - switch { - case err != nil && len(testcase.ExpectedError) == 0: - t.Errorf("unexpected error: %v", err) - case err != nil && len(testcase.ExpectedError) != 0: - if !strings.Contains(err.Error(), testcase.ExpectedError) { - t.Errorf("expected error to contain %q but got: %v", testcase.ExpectedError, err) - } - return - case err == nil && len(testcase.ExpectedError) != 0: - t.Errorf("unexpected no error") - } - - actualString := string(buf.Bytes()) - actualString = noopDir.ReplaceAllString(actualString, "/tmp/noop/") - actualString = transformedDir.ReplaceAllString(actualString, "/tmp/transformed/") - actualString = timestamp.ReplaceAllString(actualString, "YYYY-MM-DD HH:MM:SS") - actualBytes := []byte(actualString) - if !updateKustomizeExpected { - expectedBytes, err := ioutil.ReadFile(testcase.ExpectedDiff) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if !reflect.DeepEqual(actualBytes, expectedBytes) { - t.Errorf("%s\ndoesn't equal expected:\n%s\n", actualBytes, expectedBytes) - } - } else { - ioutil.WriteFile(testcase.ExpectedDiff, actualBytes, 0644) - } - -} diff --git a/pkg/diff/directory.go b/pkg/diff/directory.go deleted file mode 100644 index b4308f10c..000000000 --- a/pkg/diff/directory.go +++ /dev/null @@ -1,38 +0,0 @@ -package diff - -import ( - "io/ioutil" - "os" - "path/filepath" -) - -// directory represents a new temp directory and lets one create files in it. -type directory struct { - n string -} - -// newDirectory makes a directory instance holding a new temp directory on disk. -// The directory name is the given prefix following by a random string. -func newDirectory(prefix string) (*directory, error) { - name, err := ioutil.TempDir("", prefix+"-") - if err != nil { - return nil, err - } - - return &directory{n: name}, nil -} - -// newFile creates a new file in the directory. -func (d *directory) newFile(name string) (*os.File, error) { - return os.OpenFile(filepath.Join(d.n, name), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0700) -} - -// delete removes the directory recursively. -func (d *directory) delete() error { - return os.RemoveAll(d.n) -} - -// name is the name of the directory. -func (d *directory) name() string { - return d.n -} diff --git a/pkg/diff/program.go b/pkg/diff/program.go deleted file mode 100644 index 13137dcf0..000000000 --- a/pkg/diff/program.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package diff - -import ( - "io" - "os" - - "github.com/kubernetes-sigs/kustomize/pkg/exec" -) - -// program wraps the system diff program. -// If specified, the value of KUBERNETES_EXTERNAL_DIFF environment variable -// will be used instead of simply `diff(1)`. -type program struct { - stdout io.Writer - stderr io.Writer -} - -func newProgram(out, errOut io.Writer) *program { - return &program{ - stdout: out, - stderr: errOut, - } -} - -func (d *program) makeCommand(args ...string) exec.Cmd { - diff := "diff" - if envDiff := os.Getenv("KUBERNETES_EXTERNAL_DIFF"); envDiff != "" { - diff = envDiff - } else { - args = append([]string{"-u", "-N"}, args...) - } - cmd := exec.New().Command(diff, args...) - cmd.SetStdout(d.stdout) - cmd.SetStderr(d.stderr) - return cmd -} - -// run runs the detected diff program. `from` and `to` are the directory to diff. -func (d *program) run(from, to string) error { - d.makeCommand(from, to).Run() // Ignore diff return code - return nil -} diff --git a/pkg/diff/rundiff.go b/pkg/diff/rundiff.go deleted file mode 100644 index 56aea4dac..000000000 --- a/pkg/diff/rundiff.go +++ /dev/null @@ -1,83 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package diff runs system `diff` to compare resource collections. -package diff - -import ( - "github.com/ghodss/yaml" - - "io" - - "github.com/kubernetes-sigs/kustomize/pkg/resmap" -) - -// RunDiff runs system diff program to compare two Maps. -func RunDiff(raw, transformed resmap.ResMap, out, errOut io.Writer) (err error) { - transformedDir, err := writeYamlToNewDir(transformed, "transformed") - if err != nil { - return err - } - defer func() { - err = transformedDir.delete() - }() - - noopDir, err := writeYamlToNewDir(raw, "noop") - if err != nil { - return err - } - defer func() { - err = noopDir.delete() - }() - - return newProgram(out, errOut).run(noopDir.name(), transformedDir.name()) -} - -// writeYamlToNewDir writes each obj in ResMap to a file in a new directory. -// The directory's name will begin with the given prefix. -// Each file is named with GroupVersionKindName. -func writeYamlToNewDir(in resmap.ResMap, prefix string) (*directory, error) { - dir, err := newDirectory(prefix) - if err != nil { - return nil, err - } - - for id, obj := range in { - f, err := dir.newFile(id.GvknString()) - if err != nil { - return nil, err - } - err = write(obj, f) - f.Close() - if err != nil { - return nil, err - } - } - return dir, nil -} - -// Write the object as YAML. -func write(obj interface{}, w io.Writer) error { - if obj == nil { - return nil - } - data, err := yaml.Marshal(obj) - if err != nil { - return err - } - _, err = w.Write(data) - return err -}