Skip to content

Commit be196e0

Browse files
authored
Support configuring default namespace for kubectl/kustomize deployers (#4374)
1 parent 44c3768 commit be196e0

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/v2beta8.json

+14-2
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,11 @@
17691769
},
17701770
"KubectlDeploy": {
17711771
"properties": {
1772+
"defaultNamespace": {
1773+
"type": "string",
1774+
"description": "default namespace passed to kubectl on deployment if no other override is given.",
1775+
"x-intellij-html-description": "default namespace passed to kubectl on deployment if no other override is given."
1776+
},
17721777
"flags": {
17731778
"$ref": "#/definitions/KubectlFlags",
17741779
"description": "additional flags passed to `kubectl`.",
@@ -1796,7 +1801,8 @@
17961801
"preferredOrder": [
17971802
"manifests",
17981803
"remoteManifests",
1799-
"flags"
1804+
"flags",
1805+
"defaultNamespace"
18001806
],
18011807
"additionalProperties": false,
18021808
"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.",
@@ -1859,6 +1865,11 @@
18591865
"x-intellij-html-description": "additional args passed to <code>kustomize build</code>.",
18601866
"default": "[]"
18611867
},
1868+
"defaultNamespace": {
1869+
"type": "string",
1870+
"description": "default namespace passed to kubectl on deployment if no other override is given.",
1871+
"x-intellij-html-description": "default namespace passed to kubectl on deployment if no other override is given."
1872+
},
18621873
"flags": {
18631874
"$ref": "#/definitions/KubectlFlags",
18641875
"description": "additional flags passed to `kubectl`.",
@@ -1877,7 +1888,8 @@
18771888
"preferredOrder": [
18781889
"paths",
18791890
"flags",
1880-
"buildArgs"
1891+
"buildArgs",
1892+
"defaultNamespace"
18811893
],
18821894
"additionalProperties": false,
18831895
"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
@@ -115,7 +115,13 @@ func (h *HelmDeployer) Deploy(ctx context.Context, out io.Writer, builds []build
115115

116116
// collect namespaces
117117
for _, r := range results {
118-
if trimmed := strings.TrimSpace(r.Namespace); trimmed != "" {
118+
var namespace string
119+
namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
120+
if err != nil {
121+
return nil, fmt.Errorf("cannot parse the release namespace template: %w", err)
122+
}
123+
124+
if trimmed := strings.TrimSpace(namespace); trimmed != "" {
119125
nsMap[trimmed] = struct{}{}
120126
}
121127
}
@@ -223,7 +229,10 @@ func (h *HelmDeployer) Cleanup(ctx context.Context, out io.Writer) error {
223229
if h.namespace != "" {
224230
namespace = h.namespace
225231
} else if r.Namespace != "" {
226-
namespace = r.Namespace
232+
namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
233+
if err != nil {
234+
return fmt.Errorf("cannot parse the release namespace template: %w", err)
235+
}
227236
}
228237

229238
args := []string{"delete", releaseName}
@@ -286,7 +295,13 @@ func (h *HelmDeployer) Render(ctx context.Context, out io.Writer, builds []build
286295
}
287296

288297
if r.Namespace != "" {
289-
args = append(args, "--namespace", r.Namespace)
298+
var namespace string
299+
namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
300+
if err != nil {
301+
return fmt.Errorf("cannot parse the release namespace template: %w", err)
302+
}
303+
304+
args = append(args, "--namespace", namespace)
290305
}
291306

292307
outBuffer := new(bytes.Buffer)
@@ -340,7 +355,10 @@ func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r lates
340355
if h.namespace != "" {
341356
opts.namespace = h.namespace
342357
} else if r.Namespace != "" {
343-
opts.namespace = r.Namespace
358+
opts.namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
359+
if err != nil {
360+
return nil, fmt.Errorf("cannot parse the release namespace template: %w", err)
361+
}
344362
}
345363

346364
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
@@ -73,6 +73,21 @@ var testDeployNamespacedConfig = latest.HelmDeploy{
7373
}},
7474
}
7575

76+
var testDeployEnvTemplateNamespacedConfig = latest.HelmDeploy{
77+
Releases: []latest.HelmRelease{{
78+
Name: "skaffold-helm",
79+
ChartPath: "examples/test",
80+
ArtifactOverrides: map[string]string{
81+
"image": "skaffold-helm",
82+
},
83+
Overrides: schemautil.HelmOverrides{Values: map[string]interface{}{"foo": "bar"}},
84+
SetValues: map[string]string{
85+
"some.key": "somevalue",
86+
},
87+
Namespace: "testRelease{{.FOO}}Namespace",
88+
}},
89+
}
90+
7691
var testDeployConfigTemplated = latest.HelmDeploy{
7792
Releases: []latest.HelmRelease{{
7893
Name: "skaffold-helm",
@@ -293,6 +308,7 @@ var testDeployCreateNamespaceConfig = latest.HelmDeploy{
293308
}
294309

295310
var testNamespace = "testNamespace"
311+
var testNamespace2 = "testNamespace2"
296312

297313
var validDeployYaml = `
298314
# Source: skaffold-helm/templates/deployment.yaml
@@ -435,6 +451,7 @@ func TestHelmDeploy(t *testing.T) {
435451
force bool
436452
shouldErr bool
437453
expectedWarnings []string
454+
envs map[string]string
438455
}{
439456
{
440457
description: "deploy success",
@@ -492,6 +509,17 @@ func TestHelmDeploy(t *testing.T) {
492509
helm: testDeployNamespacedConfig,
493510
builds: testBuilds,
494511
},
512+
{
513+
description: "helm3.0 namespaced (with env template) deploy success",
514+
commands: testutil.
515+
CmdRunWithOutput("helm version --client", version30).
516+
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig").
517+
AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
518+
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").
519+
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig"),
520+
helm: testDeployEnvTemplateNamespacedConfig,
521+
builds: testBuilds,
522+
},
495523
{
496524
description: "helm3.0 namespaced context deploy success",
497525
commands: testutil.
@@ -538,6 +566,17 @@ func TestHelmDeploy(t *testing.T) {
538566
helm: testDeployNamespacedConfig,
539567
builds: testBuilds,
540568
},
569+
{
570+
description: "helm3.1 namespaced deploy (with env template) success",
571+
commands: testutil.
572+
CmdRunWithOutput("helm version --client", version31).
573+
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig").
574+
AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
575+
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").
576+
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig"),
577+
helm: testDeployEnvTemplateNamespacedConfig,
578+
builds: testBuilds,
579+
},
541580
{
542581
description: "helm3.1 namespaced context deploy success",
543582
commands: testutil.
@@ -908,6 +947,7 @@ func TestHelmCleanup(t *testing.T) {
908947
builds []build.Artifact
909948
shouldErr bool
910949
expectedWarnings []string
950+
envs map[string]string
911951
}{
912952
{
913953
description: "cleanup success",
@@ -933,6 +973,14 @@ func TestHelmCleanup(t *testing.T) {
933973
helm: testDeployNamespacedConfig,
934974
builds: testBuilds,
935975
},
976+
{
977+
description: "helm3 namespace (with env template) cleanup success",
978+
commands: testutil.
979+
CmdRunWithOutput("helm version --client", version31).
980+
AndRun("helm --kube-context kubecontext delete skaffold-helm --namespace testReleaseFOOBARNamespace --kubeconfig kubeconfig"),
981+
helm: testDeployEnvTemplateNamespacedConfig,
982+
builds: testBuilds,
983+
},
936984
{
937985
description: "helm3 namespaced context cleanup success",
938986
commands: testutil.
@@ -1163,6 +1211,7 @@ func TestHelmRender(t *testing.T) {
11631211
outputFile string
11641212
expected string
11651213
builds []build.Artifact
1214+
envs map[string]string
11661215
}{
11671216
{
11681217
description: "error if version can't be retrieved",
@@ -1217,7 +1266,7 @@ func TestHelmRender(t *testing.T) {
12171266
shouldErr: false,
12181267
commands: testutil.
12191268
CmdRunWithOutput("helm version --client", version31).
1220-
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"),
1269+
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"),
12211270
helm: testDeployConfigTemplated,
12221271
builds: []build.Artifact{
12231272
{
@@ -1237,6 +1286,18 @@ func TestHelmRender(t *testing.T) {
12371286
Tag: "skaffold-helm:tag1",
12381287
}},
12391288
},
1289+
{
1290+
description: "render with namespace",
1291+
shouldErr: false,
1292+
commands: testutil.CmdRunWithOutput("helm version --client", version31).
1293+
AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --set-string image=skaffold-helm:tag1 --set some.key=somevalue --namespace testReleaseFOOBARNamespace --kubeconfig kubeconfig"),
1294+
helm: testDeployEnvTemplateNamespacedConfig,
1295+
builds: []build.Artifact{
1296+
{
1297+
ImageName: "skaffold-helm",
1298+
Tag: "skaffold-helm:tag1",
1299+
}},
1300+
},
12401301
}
12411302
for _, test := range tests {
12421303
testutil.Run(t, test.description, func(t *testutil.T) {
@@ -1245,6 +1306,8 @@ func TestHelmRender(t *testing.T) {
12451306
file = t.NewTempDir().Path(test.outputFile)
12461307
}
12471308

1309+
t.Override(&util.OSEnviron, func() []string { return []string{"FOO=FOOBAR"} })
1310+
12481311
deployer := NewHelmDeployer(&helmConfig{
12491312
helm: test.helm,
12501313
}, 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)