Skip to content

Commit f0be4d1

Browse files
committed
Support configuring default namespace for kubectl/kustomize deployers
1 parent 4cccbd6 commit f0be4d1

File tree

22 files changed

+464
-178
lines changed

22 files changed

+464
-178
lines changed

docs/content/en/docs/environment/templating.md

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ List of fields that support templating:
1919
* `build.tagPolicy.envTemplate.template` (see [envTemplate tagger]({{< relref "/docs/pipeline-stages/taggers#envtemplate-using-values-of-environment-variables-as-tags)" >}}))
2020
* `deploy.helm.releases.setValueTemplates` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
2121
* `deploy.helm.releases.name` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
22+
* `deploy.helm.releases.namespace` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
23+
* `deploy.kubectl.defaultNamespace`
24+
* `deploy.kustomize.defaultNamespace`
2225

2326
_Please note, this list is not exhaustive._
2427

docs/content/en/schemas/v2beta7.json

+14-2
Original file line numberDiff line numberDiff line change
@@ -1745,6 +1745,11 @@
17451745
},
17461746
"KubectlDeploy": {
17471747
"properties": {
1748+
"defaultNamespace": {
1749+
"type": "string",
1750+
"description": "default namespace passed to kubectl on deployment if no other override is given.",
1751+
"x-intellij-html-description": "default namespace passed to kubectl on deployment if no other override is given."
1752+
},
17481753
"flags": {
17491754
"$ref": "#/definitions/KubectlFlags",
17501755
"description": "additional flags passed to `kubectl`.",
@@ -1772,7 +1777,8 @@
17721777
"preferredOrder": [
17731778
"manifests",
17741779
"remoteManifests",
1775-
"flags"
1780+
"flags",
1781+
"defaultNamespace"
17761782
],
17771783
"additionalProperties": false,
17781784
"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.",
@@ -1835,6 +1841,11 @@
18351841
"x-intellij-html-description": "additional args passed to <code>kustomize build</code>.",
18361842
"default": "[]"
18371843
},
1844+
"defaultNamespace": {
1845+
"type": "string",
1846+
"description": "default namespace passed to kubectl on deployment if no other override is given.",
1847+
"x-intellij-html-description": "default namespace passed to kubectl on deployment if no other override is given."
1848+
},
18381849
"flags": {
18391850
"$ref": "#/definitions/KubectlFlags",
18401851
"description": "additional flags passed to `kubectl`.",
@@ -1853,7 +1864,8 @@
18531864
"preferredOrder": [
18541865
"paths",
18551866
"flags",
1856-
"buildArgs"
1867+
"buildArgs",
1868+
"defaultNamespace"
18571869
],
18581870
"additionalProperties": false,
18591871
"description": "*beta* uses the `kustomize` CLI to \"patch\" a deployment for a target environment.",

integration/port_forward_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func TestPortForward(t *testing.T) {
4646
Opts: config.SkaffoldOptions{
4747
Namespace: ns.Name,
4848
},
49-
})
49+
}, "")
5050

5151
logrus.SetLevel(logrus.TraceLevel)
5252
portforward.SimulateDevCycle(t, kubectlCLI, ns.Name)

integration/render_test.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
"github.com/GoogleContainerTools/skaffold/integration/skaffold"
3232
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
33+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
3334
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy"
3435
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
3536
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
@@ -75,7 +76,7 @@ spec:
7576
t.NewTempDir().
7677
Write("deployment.yaml", test.input).
7778
Chdir()
78-
deployer := deploy.NewKubectlDeployer(&runcontext.RunContext{
79+
deployer, err := deploy.NewKubectlDeployer(&runcontext.RunContext{
7980
WorkingDir: ".",
8081
Cfg: latest.Pipeline{
8182
Deploy: latest.DeployConfig{
@@ -87,8 +88,9 @@ spec:
8788
},
8889
},
8990
}, nil)
91+
t.RequireNoError(err)
9092
var b bytes.Buffer
91-
err := deployer.Render(context.Background(), &b, test.builds, false, test.renderPath)
93+
err = deployer.Render(context.Background(), &b, test.builds, false, test.renderPath)
9294

9395
t.CheckNoError(err)
9496
dat, err := ioutil.ReadFile(test.renderPath)
@@ -229,7 +231,7 @@ spec:
229231
Write("deployment.yaml", test.input).
230232
Chdir()
231233

232-
deployer := deploy.NewKubectlDeployer(&runcontext.RunContext{
234+
deployer, err := deploy.NewKubectlDeployer(&runcontext.RunContext{
233235
WorkingDir: ".",
234236
Cfg: latest.Pipeline{
235237
Deploy: latest.DeployConfig{
@@ -240,9 +242,13 @@ spec:
240242
},
241243
},
242244
},
245+
Opts: config.SkaffoldOptions{
246+
AddSkaffoldLabels: true,
247+
},
243248
}, nil)
249+
t.RequireNoError(err)
244250
var b bytes.Buffer
245-
err := deployer.Render(context.Background(), &b, test.builds, false, "")
251+
err = deployer.Render(context.Background(), &b, test.builds, false, "")
246252

247253
t.CheckNoError(err)
248254
t.CheckDeepEqual(test.expectedOut, b.String())

pkg/skaffold/build/cluster/types.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func NewBuilder(cfg Config) (*Builder, error) {
5858

5959
return &Builder{
6060
ClusterDetails: cfg.Pipeline().Build.Cluster,
61-
kubectlcli: kubectl.NewCLI(cfg),
61+
kubectlcli: kubectl.NewCLI(cfg, ""),
6262
timeout: timeout,
6363
kubeContext: cfg.GetKubeContext(),
6464
insecureRegistries: cfg.GetInsecureRegistries(),

pkg/skaffold/deploy/helm.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,13 @@ func (h *HelmDeployer) Deploy(ctx context.Context, out io.Writer, builds []build
113113

114114
// collect namespaces
115115
for _, r := range results {
116-
if trimmed := strings.TrimSpace(r.Namespace); trimmed != "" {
116+
var namespace string
117+
namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
118+
if err != nil {
119+
return nil, fmt.Errorf("cannot parse the release namespace template: %w", err)
120+
}
121+
122+
if trimmed := strings.TrimSpace(namespace); trimmed != "" {
117123
nsMap[trimmed] = struct{}{}
118124
}
119125
}
@@ -221,7 +227,10 @@ func (h *HelmDeployer) Cleanup(ctx context.Context, out io.Writer) error {
221227
if h.namespace != "" {
222228
namespace = h.namespace
223229
} else if r.Namespace != "" {
224-
namespace = r.Namespace
230+
namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
231+
if err != nil {
232+
return fmt.Errorf("cannot parse the release namespace template: %w", err)
233+
}
225234
}
226235

227236
args := []string{"delete", releaseName}
@@ -284,7 +293,13 @@ func (h *HelmDeployer) Render(ctx context.Context, out io.Writer, builds []build
284293
}
285294

286295
if r.Namespace != "" {
287-
args = append(args, "--namespace", r.Namespace)
296+
var namespace string
297+
namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
298+
if err != nil {
299+
return fmt.Errorf("cannot parse the release namespace template: %w", err)
300+
}
301+
302+
args = append(args, "--namespace", namespace)
288303
}
289304

290305
if err := h.exec(ctx, renderedManifests, false, args...); err != nil {
@@ -336,7 +351,10 @@ func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r lates
336351
if h.namespace != "" {
337352
opts.namespace = h.namespace
338353
} else if r.Namespace != "" {
339-
opts.namespace = r.Namespace
354+
opts.namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
355+
if err != nil {
356+
return nil, fmt.Errorf("cannot parse the release namespace template: %w", err)
357+
}
340358
}
341359

342360
if err := h.exec(ctx, ioutil.Discard, false, getArgs(helmVersion, releaseName, opts.namespace)...); err != nil {

pkg/skaffold/deploy/helm_test.go

+64-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,21 @@ var testDeployNamespacedConfig = latest.HelmDeploy{
7171
}},
7272
}
7373

74+
var testDeployEnvTemplateNamespacedConfig = latest.HelmDeploy{
75+
Releases: []latest.HelmRelease{{
76+
Name: "skaffold-helm",
77+
ChartPath: "examples/test",
78+
ArtifactOverrides: map[string]string{
79+
"image": "skaffold-helm",
80+
},
81+
Overrides: schemautil.HelmOverrides{Values: map[string]interface{}{"foo": "bar"}},
82+
SetValues: map[string]string{
83+
"some.key": "somevalue",
84+
},
85+
Namespace: "testRelease{{.FOO}}Namespace",
86+
}},
87+
}
88+
7489
var testDeployConfigTemplated = latest.HelmDeploy{
7590
Releases: []latest.HelmRelease{{
7691
Name: "skaffold-helm",
@@ -273,6 +288,7 @@ var testTwoReleases = latest.HelmDeploy{
273288
}
274289

275290
var testNamespace = "testNamespace"
291+
var testNamespace2 = "testNamespace2"
276292

277293
var validDeployYaml = `
278294
# Source: skaffold-helm/templates/deployment.yaml
@@ -410,6 +426,7 @@ func TestHelmDeploy(t *testing.T) {
410426
force bool
411427
shouldErr bool
412428
expectedWarnings []string
429+
envs map[string]string
413430
}{
414431
{
415432
description: "deploy success",
@@ -467,6 +484,17 @@ func TestHelmDeploy(t *testing.T) {
467484
helm: testDeployNamespacedConfig,
468485
builds: testBuilds,
469486
},
487+
{
488+
description: "helm3.0 namespaced (with env template) deploy success",
489+
commands: testutil.
490+
CmdRunWithOutput("helm version --client", version30).
491+
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig").
492+
AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
493+
AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testReleaseFOOBARNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig").
494+
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig"),
495+
helm: testDeployEnvTemplateNamespacedConfig,
496+
builds: testBuilds,
497+
},
470498
{
471499
description: "helm3.0 namespaced context deploy success",
472500
commands: testutil.
@@ -513,6 +541,17 @@ func TestHelmDeploy(t *testing.T) {
513541
helm: testDeployNamespacedConfig,
514542
builds: testBuilds,
515543
},
544+
{
545+
description: "helm3.1 namespaced deploy (with env template) success",
546+
commands: testutil.
547+
CmdRunWithOutput("helm version --client", version31).
548+
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig").
549+
AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
550+
AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testReleaseFOOBARNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig").
551+
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig"),
552+
helm: testDeployEnvTemplateNamespacedConfig,
553+
builds: testBuilds,
554+
},
516555
{
517556
description: "helm3.1 namespaced context deploy success",
518557
commands: testutil.
@@ -851,6 +890,7 @@ func TestHelmCleanup(t *testing.T) {
851890
builds []build.Artifact
852891
shouldErr bool
853892
expectedWarnings []string
893+
envs map[string]string
854894
}{
855895
{
856896
description: "cleanup success",
@@ -876,6 +916,14 @@ func TestHelmCleanup(t *testing.T) {
876916
helm: testDeployNamespacedConfig,
877917
builds: testBuilds,
878918
},
919+
{
920+
description: "helm3 namespace (with env template) cleanup success",
921+
commands: testutil.
922+
CmdRunWithOutput("helm version --client", version31).
923+
AndRun("helm --kube-context kubecontext delete skaffold-helm --namespace testReleaseFOOBARNamespace --kubeconfig kubeconfig"),
924+
helm: testDeployEnvTemplateNamespacedConfig,
925+
builds: testBuilds,
926+
},
879927
{
880928
description: "helm3 namespaced context cleanup success",
881929
commands: testutil.
@@ -1106,6 +1154,7 @@ func TestHelmRender(t *testing.T) {
11061154
outputFile string
11071155
expected string
11081156
builds []build.Artifact
1157+
envs map[string]string
11091158
}{
11101159
{
11111160
description: "error if version can't be retrieved",
@@ -1160,7 +1209,7 @@ func TestHelmRender(t *testing.T) {
11601209
shouldErr: false,
11611210
commands: testutil.
11621211
CmdRunWithOutput("helm version --client", version31).
1163-
AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --set-string image=skaffold-helm:tag1 --set image.name=skaffold-helm --set image.tag=skaffold-helm:tag1 --set missing.key=<no value> --set other.key=<no value> --set some.key=somevalue --kubeconfig kubeconfig"),
1212+
AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --set-string image=skaffold-helm:tag1 --set image.name=skaffold-helm --set image.tag=skaffold-helm:tag1 --set missing.key=<no value> --set other.key=FOOBAR --set some.key=somevalue --kubeconfig kubeconfig"),
11641213
helm: testDeployConfigTemplated,
11651214
builds: []build.Artifact{
11661215
{
@@ -1180,6 +1229,18 @@ func TestHelmRender(t *testing.T) {
11801229
Tag: "skaffold-helm:tag1",
11811230
}},
11821231
},
1232+
{
1233+
description: "render with namespace",
1234+
shouldErr: false,
1235+
commands: testutil.CmdRunWithOutput("helm version --client", version31).
1236+
AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --set-string image=skaffold-helm:tag1 --set some.key=somevalue --namespace testReleaseFOOBARNamespace --kubeconfig kubeconfig"),
1237+
helm: testDeployEnvTemplateNamespacedConfig,
1238+
builds: []build.Artifact{
1239+
{
1240+
ImageName: "skaffold-helm",
1241+
Tag: "skaffold-helm:tag1",
1242+
}},
1243+
},
11831244
}
11841245
for _, test := range tests {
11851246
testutil.Run(t, test.description, func(t *testutil.T) {
@@ -1188,6 +1249,8 @@ func TestHelmRender(t *testing.T) {
11881249
file = t.NewTempDir().Path(test.outputFile)
11891250
}
11901251

1252+
t.Override(&util.OSEnviron, func() []string { return []string{"FOO=FOOBAR"} })
1253+
11911254
deployer := NewHelmDeployer(&helmConfig{
11921255
helm: test.helm,
11931256
}, nil)

pkg/skaffold/deploy/kubectl.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,26 @@ type Config interface {
6767

6868
// NewKubectlDeployer returns a new KubectlDeployer for a DeployConfig filled
6969
// with the needed configuration for `kubectl apply`
70-
func NewKubectlDeployer(cfg Config, labels map[string]string) *KubectlDeployer {
70+
func NewKubectlDeployer(cfg Config, labels map[string]string) (*KubectlDeployer, error) {
71+
defaultNamespace := ""
72+
if cfg.Pipeline().Deploy.KubectlDeploy.DefaultNamespace != nil {
73+
var err error
74+
defaultNamespace, err = util.ExpandEnvTemplate(*cfg.Pipeline().Deploy.KubectlDeploy.DefaultNamespace, nil)
75+
if err != nil {
76+
return nil, err
77+
}
78+
}
79+
7180
return &KubectlDeployer{
7281
KubectlDeploy: cfg.Pipeline().Deploy.KubectlDeploy,
7382
workingDir: cfg.GetWorkingDir(),
7483
globalConfig: cfg.GlobalConfig(),
7584
defaultRepo: cfg.DefaultRepo(),
76-
kubectl: deploy.NewCLI(cfg, cfg.Pipeline().Deploy.KubectlDeploy.Flags),
85+
kubectl: deploy.NewCLI(cfg, cfg.Pipeline().Deploy.KubectlDeploy.Flags, defaultNamespace),
7786
insecureRegistries: cfg.GetInsecureRegistries(),
7887
skipRender: cfg.SkipRender(),
7988
labels: labels,
80-
}
89+
}, nil
8190
}
8291

8392
// Deploy templates the provided manifests with a simple `find and replace` and

pkg/skaffold/deploy/kubectl/cli.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ type Config interface {
4747
WaitForDeletions() config.WaitForDeletions
4848
}
4949

50-
func NewCLI(cfg Config, flags latest.KubectlFlags) CLI {
50+
func NewCLI(cfg Config, flags latest.KubectlFlags, defaultNameSpace string) CLI {
5151
return CLI{
52-
CLI: pkgkubectl.NewCLI(cfg),
52+
CLI: pkgkubectl.NewCLI(cfg, defaultNameSpace),
5353
Flags: flags,
5454
forceDeploy: cfg.ForceDeploy(),
5555
waitForDeletions: cfg.WaitForDeletions(),

0 commit comments

Comments
 (0)