diff --git a/docs/content/en/schemas/v2beta5.json b/docs/content/en/schemas/v2beta5.json index 41213502f93..07eaca2d230 100755 --- a/docs/content/en/schemas/v2beta5.json +++ b/docs/content/en/schemas/v2beta5.json @@ -1568,6 +1568,11 @@ }, "KubectlDeploy": { "properties": { + "defaultNamespace": { + "type": "string", + "description": "default namespace passed to kubectl on deployment if no other override is given.", + "x-intellij-html-description": "default namespace passed to kubectl on deployment if no other override is given." + }, "flags": { "$ref": "#/definitions/KubectlFlags", "description": "additional flags passed to `kubectl`.", @@ -1595,7 +1600,8 @@ "preferredOrder": [ "manifests", "remoteManifests", - "flags" + "flags", + "defaultNamespace" ], "additionalProperties": false, "description": "*beta* uses a client side `kubectl apply` to deploy manifests. You'll need a `kubectl` CLI version installed that's compatible with your cluster.", @@ -1658,6 +1664,11 @@ "x-intellij-html-description": "additional args passed to kustomize build.", "default": "[]" }, + "defaultNamespace": { + "type": "string", + "description": "default namespace passed to kubectl on deployment if no other override is given.", + "x-intellij-html-description": "default namespace passed to kubectl on deployment if no other override is given." + }, "flags": { "$ref": "#/definitions/KubectlFlags", "description": "additional flags passed to `kubectl`.", @@ -1676,7 +1687,8 @@ "preferredOrder": [ "paths", "flags", - "buildArgs" + "buildArgs", + "defaultNamespace" ], "additionalProperties": false, "description": "*beta* uses the `kustomize` CLI to \"patch\" a deployment for a target environment.", diff --git a/pkg/skaffold/deploy/helm_test.go b/pkg/skaffold/deploy/helm_test.go index ebf6c3ddefb..600023e78b5 100644 --- a/pkg/skaffold/deploy/helm_test.go +++ b/pkg/skaffold/deploy/helm_test.go @@ -261,6 +261,7 @@ var testTwoReleases = latest.HelmDeploy{ } var testNamespace = "testNamespace" +var testNamespace2 = "testNamespace2" var validDeployYaml = ` # Source: skaffold-helm/templates/deployment.yaml diff --git a/pkg/skaffold/deploy/kubectl.go b/pkg/skaffold/deploy/kubectl.go index 34aa10cfed0..f253b03868f 100644 --- a/pkg/skaffold/deploy/kubectl.go +++ b/pkg/skaffold/deploy/kubectl.go @@ -59,13 +59,18 @@ type KubectlDeployer struct { // NewKubectlDeployer returns a new KubectlDeployer for a DeployConfig filled // with the needed configuration for `kubectl apply` func NewKubectlDeployer(runCtx *runcontext.RunContext) *KubectlDeployer { + defaultNamespace := "" + if runCtx.Cfg.Deploy.KubectlDeploy.DefaultNamespace != nil { + defaultNamespace = *runCtx.Cfg.Deploy.KubectlDeploy.DefaultNamespace + } + return &KubectlDeployer{ KubectlDeploy: runCtx.Cfg.Deploy.KubectlDeploy, workingDir: runCtx.WorkingDir, globalConfig: runCtx.Opts.GlobalConfig, defaultRepo: runCtx.Opts.DefaultRepo.Value(), kubectl: deploy.CLI{ - CLI: kubectl.NewFromRunContext(runCtx), + CLI: kubectl.NewFromRunContextAndDefaultNamespace(runCtx, defaultNamespace), Flags: runCtx.Cfg.Deploy.KubectlDeploy.Flags, ForceDeploy: runCtx.Opts.Force, }, diff --git a/pkg/skaffold/deploy/kubectl_test.go b/pkg/skaffold/deploy/kubectl_test.go index 84c920a23b5..65a810d7aaa 100644 --- a/pkg/skaffold/deploy/kubectl_test.go +++ b/pkg/skaffold/deploy/kubectl_test.go @@ -61,12 +61,13 @@ spec: func TestKubectlDeploy(t *testing.T) { tests := []struct { - description string - cfg *latest.KubectlDeploy - builds []build.Artifact - commands util.Command - shouldErr bool - forceDeploy bool + description string + cfg *latest.KubectlDeploy + builds []build.Artifact + commands util.Command + shouldErr bool + forceDeploy bool + skipSkaffoldNamespaceOption bool }{ { description: "no manifest", @@ -133,6 +134,22 @@ func TestKubectlDeploy(t *testing.T) { Tag: "leeroy-web:123", }}, }, + { + description: "deploy success (default namespace)", + cfg: &latest.KubectlDeploy{ + Manifests: []string{"deployment.yaml"}, + DefaultNamespace: &testNamespace2, + }, + commands: testutil. + CmdRunOut("kubectl version --client -ojson", kubectlVersion118). + AndRunOut("kubectl --context kubecontext --namespace testNamespace2 create --dry-run=client -oyaml -f deployment.yaml", deploymentWebYAML). + AndRun("kubectl --context kubecontext --namespace testNamespace2 apply -f -"), + builds: []build.Artifact{{ + ImageName: "leeroy-web", + Tag: "leeroy-web:123", + }}, + skipSkaffoldNamespaceOption: true, + }, { description: "http manifest", cfg: &latest.KubectlDeploy{ @@ -191,6 +208,11 @@ func TestKubectlDeploy(t *testing.T) { Touch("empty.ignored"). Chdir() + skaffoldNamespaceOption := "" + if !test.skipSkaffoldNamespaceOption { + skaffoldNamespaceOption = testNamespace + } + k := NewKubectlDeployer(&runcontext.RunContext{ WorkingDir: ".", Cfg: latest.Pipeline{ @@ -202,7 +224,7 @@ func TestKubectlDeploy(t *testing.T) { }, KubeContext: testKubeContext, Opts: config.SkaffoldOptions{ - Namespace: testNamespace, + Namespace: skaffoldNamespaceOption, Force: test.forceDeploy, }, }) diff --git a/pkg/skaffold/deploy/kustomize.go b/pkg/skaffold/deploy/kustomize.go index 2bbbf26d4f8..ad83dbdae58 100644 --- a/pkg/skaffold/deploy/kustomize.go +++ b/pkg/skaffold/deploy/kustomize.go @@ -96,10 +96,15 @@ type KustomizeDeployer struct { } func NewKustomizeDeployer(runCtx *runcontext.RunContext) *KustomizeDeployer { + defaultNamespace := "" + if runCtx.Cfg.Deploy.KustomizeDeploy.DefaultNamespace != nil { + defaultNamespace = *runCtx.Cfg.Deploy.KustomizeDeploy.DefaultNamespace + } + return &KustomizeDeployer{ KustomizeDeploy: runCtx.Cfg.Deploy.KustomizeDeploy, kubectl: deploy.CLI{ - CLI: kubectl.NewFromRunContext(runCtx), + CLI: kubectl.NewFromRunContextAndDefaultNamespace(runCtx, defaultNamespace), Flags: runCtx.Cfg.Deploy.KustomizeDeploy.Flags, ForceDeploy: runCtx.Opts.Force, }, diff --git a/pkg/skaffold/deploy/kustomize_test.go b/pkg/skaffold/deploy/kustomize_test.go index 5bd0bccb97b..dccd33a749b 100644 --- a/pkg/skaffold/deploy/kustomize_test.go +++ b/pkg/skaffold/deploy/kustomize_test.go @@ -34,12 +34,13 @@ import ( func TestKustomizeDeploy(t *testing.T) { tests := []struct { - description string - cfg *latest.KustomizeDeploy - builds []build.Artifact - commands util.Command - shouldErr bool - forceDeploy bool + description string + cfg *latest.KustomizeDeploy + builds []build.Artifact + commands util.Command + shouldErr bool + forceDeploy bool + skipSkaffoldNamespaceOption bool }{ { description: "no manifest", @@ -65,6 +66,23 @@ func TestKustomizeDeploy(t *testing.T) { }}, forceDeploy: true, }, + { + description: "deploy success (default namespace)", + cfg: &latest.KustomizeDeploy{ + KustomizePaths: []string{"."}, + DefaultNamespace: &testNamespace2, + }, + commands: testutil. + CmdRunOut("kubectl version --client -ojson", kubectlVersion112). + AndRunOut("kustomize build .", deploymentWebYAML). + AndRun("kubectl --context kubecontext --namespace testNamespace2 apply -f - --force --grace-period=0"), + builds: []build.Artifact{{ + ImageName: "leeroy-web", + Tag: "leeroy-web:123", + }}, + forceDeploy: true, + skipSkaffoldNamespaceOption: true, + }, { description: "deploy success with multiple kustomizations", cfg: &latest.KustomizeDeploy{ @@ -94,6 +112,11 @@ func TestKustomizeDeploy(t *testing.T) { t.NewTempDir(). Chdir() + skaffoldNamespaceOption := "" + if !test.skipSkaffoldNamespaceOption { + skaffoldNamespaceOption = testNamespace + } + k := NewKustomizeDeployer(&runcontext.RunContext{ WorkingDir: ".", Cfg: latest.Pipeline{ @@ -105,7 +128,7 @@ func TestKustomizeDeploy(t *testing.T) { }, KubeContext: testKubeContext, Opts: config.SkaffoldOptions{ - Namespace: testNamespace, + Namespace: skaffoldNamespaceOption, Force: test.forceDeploy, }, }) diff --git a/pkg/skaffold/kubectl/cli.go b/pkg/skaffold/kubectl/cli.go index 611f8f8dbb5..5a1aa081f14 100644 --- a/pkg/skaffold/kubectl/cli.go +++ b/pkg/skaffold/kubectl/cli.go @@ -44,6 +44,21 @@ func NewFromRunContext(runCtx *runcontext.RunContext) *CLI { } } +// NewFromRunContextAndDefaultNamespace creates a new kubectl CLI whereby the namespace from +// command line / environment variable takes precedence over "default namespace" defined in +// configuration +func NewFromRunContextAndDefaultNamespace(runCtx *runcontext.RunContext, defaultNamespace string) *CLI { + ns := defaultNamespace + if runCtx.Opts.Namespace != "" { + ns = runCtx.Opts.Namespace + } + return &CLI{ + KubeContext: runCtx.KubeContext, + KubeConfig: runCtx.Opts.KubeConfig, + Namespace: ns, + } +} + // Command creates the underlying exec.CommandContext. This allows low-level control of the executed command. func (c *CLI) Command(ctx context.Context, command string, arg ...string) *exec.Cmd { args := c.args(command, "", arg...) diff --git a/pkg/skaffold/schema/latest/config.go b/pkg/skaffold/schema/latest/config.go index 98f7921b412..91e73bc4b4e 100644 --- a/pkg/skaffold/schema/latest/config.go +++ b/pkg/skaffold/schema/latest/config.go @@ -438,6 +438,9 @@ type KubectlDeploy struct { // Flags are additional flags passed to `kubectl`. Flags KubectlFlags `yaml:"flags,omitempty"` + + // DefaultNamespace is the default namespace passed to kubectl on deployment if no other override is given. + DefaultNamespace *string `yaml:"defaultNamespace,omitempty"` } // KubectlFlags are additional flags passed on the command @@ -492,6 +495,9 @@ type KustomizeDeploy struct { // BuildArgs are additional args passed to `kustomize build`. BuildArgs []string `yaml:"buildArgs,omitempty"` + + // DefaultNamespace is the default namespace passed to kubectl on deployment if no other override is given. + DefaultNamespace *string `yaml:"defaultNamespace,omitempty"` } // HelmRelease describes a helm release to be deployed.