forked from kubernetes-sigs/kustomize
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add localize command handle (kubernetes-sigs#4959)
* Add localize command handle * Align to kustomize command conventions * Print success msg
- Loading branch information
1 parent
3370177
commit 2361660
Showing
3 changed files
with
253 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,98 @@ | ||
// Copyright 2022 The Kubernetes Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package localize | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"log" | ||
|
||
"github.com/spf13/cobra" | ||
lclzr "sigs.k8s.io/kustomize/api/krusty/localizer" | ||
"sigs.k8s.io/kustomize/kyaml/errors" | ||
"sigs.k8s.io/kustomize/kyaml/filesys" | ||
) | ||
|
||
const numArgs = 2 | ||
|
||
type arguments struct { | ||
target string | ||
dest string | ||
} | ||
|
||
type flags struct { | ||
scope string | ||
} | ||
|
||
// NewCmdLocalize returns a new localize command. | ||
func NewCmdLocalize(fs filesys.FileSystem, writer io.Writer) *cobra.Command { | ||
log.SetOutput(writer) | ||
var f flags | ||
cmd := &cobra.Command{ | ||
Use: "localize [target [destination]]", | ||
Short: "[Alpha] Creates localized copy of target kustomization root at destination", | ||
Long: `[Alpha] Creates copy of target kustomization directory or | ||
versioned URL at destination, where remote references in the original | ||
are replaced by local references to the downloaded remote content. | ||
If target is not specified, the current working directory will be used. | ||
Destination is a path to a new directory in an existing directory. If | ||
destination is not specified, a new directory will be created in the current | ||
working directory. | ||
For details, see: https://kubectl.docs.kubernetes.io/references/kustomize/cmd/ | ||
Disclaimer: | ||
This command does not yet localize helm or KRM plugin fields. This command also | ||
alphabetizes kustomization fields in the localized copy. | ||
`, | ||
Example: ` | ||
# Localize the current working directory, with default scope and destination | ||
kustomize localize | ||
# Localize some local directory, with scope and default destination | ||
kustomize localize /home/path/scope/target --scope /home/path/scope | ||
# Localize remote at set destination relative to working directory | ||
kustomize localize https://github.com/kubernetes-sigs/kustomize//api/krusty/testdata/localize/simple?ref=v4.5.7 path/non-existing-dir | ||
`, | ||
SilenceUsage: true, | ||
Args: cobra.MaximumNArgs(numArgs), | ||
RunE: func(cmd *cobra.Command, rawArgs []string) error { | ||
args := matchArgs(rawArgs) | ||
dst, err := lclzr.Run(fs, args.target, f.scope, args.dest) | ||
if err != nil { | ||
return errors.Wrap(err) | ||
} | ||
successMsg := fmt.Sprintf("SUCCESS: localized %q to directory %s\n", args.target, dst) | ||
_, err = writer.Write([]byte(successMsg)) | ||
return errors.Wrap(err) | ||
}, | ||
} | ||
// no shorthand to avoid conflation with other flags | ||
cmd.Flags().StringVar(&f.scope, | ||
"scope", | ||
"", | ||
`Path to directory inside of which localize is limited to running. | ||
Cannot specify for remote targets, as scope is by default the containing repo. | ||
If not specified for local target, scope defaults to target. | ||
`) | ||
return cmd | ||
} | ||
|
||
// matchArgs matches user-entered userArgs, which cannot exceed max length, with | ||
// arguments. | ||
func matchArgs(rawArgs []string) arguments { | ||
var args arguments | ||
switch len(rawArgs) { | ||
case numArgs: | ||
args.dest = rawArgs[1] | ||
fallthrough | ||
case 1: | ||
args.target = rawArgs[0] | ||
case 0: | ||
args.target = filesys.SelfDir | ||
} | ||
return args | ||
} |
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,153 @@ | ||
// Copyright 2022 The Kubernetes Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package localize_test | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"log" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
loctest "sigs.k8s.io/kustomize/api/testutils/localizertest" | ||
"sigs.k8s.io/kustomize/kustomize/v4/commands/localize" | ||
) | ||
|
||
const deployment = `apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: nginx-deployment | ||
labels: | ||
app: nginx | ||
spec: | ||
replicas: 3 | ||
selector: | ||
matchLabels: | ||
app: nginx | ||
template: | ||
metadata: | ||
labels: | ||
app: nginx | ||
spec: | ||
containers: | ||
- name: nginx | ||
image: nginx:1.14.2 | ||
ports: | ||
- containerPort: 80 | ||
` | ||
|
||
func TestScopeFlag(t *testing.T) { | ||
kustomizations := map[string]string{ | ||
filepath.Join("target", "kustomization.yaml"): fmt.Sprintf(`resources: | ||
- %s | ||
`, filepath.Join("..", "base")), | ||
filepath.Join("base", "kustomization.yaml"): `resources: | ||
- deployment.yaml | ||
`, | ||
filepath.Join("base", "deployment.yaml"): deployment, | ||
} | ||
expected, actual, testDir := loctest.PrepareFs(t, []string{ | ||
"target", | ||
"base", | ||
}, kustomizations) | ||
|
||
cmd := localize.NewCmdLocalize(actual, new(bytes.Buffer)) | ||
require.NoError(t, cmd.Flags().Set("scope", testDir.String())) | ||
err := cmd.RunE(cmd, []string{ | ||
testDir.Join("target"), | ||
testDir.Join("dst"), | ||
}) | ||
require.NoError(t, err) | ||
|
||
loctest.SetupDir(t, expected, testDir.Join("dst"), kustomizations) | ||
loctest.CheckFs(t, testDir.String(), expected, actual) | ||
} | ||
|
||
func TestOptionalArgs(t *testing.T) { | ||
for name, args := range map[string][]string{ | ||
"no_target": {}, | ||
"no_dst": {"."}, | ||
} { | ||
t.Run(name, func(t *testing.T) { | ||
kust := map[string]string{ | ||
"kustomization.yaml": `resources: | ||
- deployment.yaml | ||
`, | ||
"deployment.yaml": deployment, | ||
} | ||
expected, actual, testDir := loctest.PrepareFs(t, []string{ | ||
"target", | ||
}, nil) | ||
target := testDir.Join("target") | ||
loctest.SetupDir(t, actual, target, kust) | ||
loctest.SetWorkingDir(t, target) | ||
|
||
buffy := new(bytes.Buffer) | ||
cmd := localize.NewCmdLocalize(actual, buffy) | ||
err := cmd.RunE(cmd, args) | ||
require.NoError(t, err) | ||
|
||
loctest.SetupDir(t, expected, target, kust) | ||
dst := filepath.Join(target, "localized-target") | ||
loctest.SetupDir(t, expected, dst, kust) | ||
loctest.CheckFs(t, testDir.String(), expected, actual) | ||
|
||
successMsg := fmt.Sprintf(`SUCCESS: localized "." to directory %s | ||
`, dst) | ||
require.Equal(t, successMsg, buffy.String()) | ||
}) | ||
} | ||
} | ||
|
||
func TestOutput(t *testing.T) { | ||
kustomization := map[string]string{ | ||
"kustomization.yaml": `namePrefix: test- | ||
`, | ||
} | ||
expected, actual, target := loctest.PrepareFs(t, nil, kustomization) | ||
|
||
buffy := new(bytes.Buffer) | ||
cmd := localize.NewCmdLocalize(actual, buffy) | ||
err := cmd.RunE(cmd, []string{ | ||
target.String(), | ||
target.Join("dst"), | ||
}) | ||
require.NoError(t, err) | ||
|
||
loctest.SetupDir(t, expected, target.Join("dst"), kustomization) | ||
loctest.CheckFs(t, target.String(), expected, actual) | ||
|
||
successMsg := fmt.Sprintf(`SUCCESS: localized "%s" to directory %s | ||
`, target.String(), target.Join("dst")) | ||
require.Equal(t, successMsg, buffy.String()) | ||
|
||
const msg = "Check that cmd log output is hooked to buffy." | ||
log.Print(msg) | ||
require.Contains(t, buffy.String(), msg) | ||
} | ||
|
||
func TestAlpha(t *testing.T) { | ||
_, actual, _ := loctest.PrepareFs(t, nil, map[string]string{ | ||
"kustomization.yaml": `namePrefix: test-`, | ||
}) | ||
|
||
cmd := localize.NewCmdLocalize(actual, new(bytes.Buffer)) | ||
require.Contains(t, cmd.Short, "[Alpha]") | ||
require.Contains(t, cmd.Long, "[Alpha]") | ||
} | ||
|
||
func TestTooManyArgs(t *testing.T) { | ||
_, actual, target := loctest.PrepareFs(t, nil, map[string]string{ | ||
"kustomization.yaml": `namePrefix: test-`, | ||
}) | ||
|
||
cmd := localize.NewCmdLocalize(actual, new(bytes.Buffer)) | ||
err := cmd.Args(cmd, []string{ | ||
target.String(), | ||
target.Join("dst"), | ||
target.String(), | ||
}) | ||
require.EqualError(t, err, "accepts at most 2 arg(s), received 3") | ||
} |