Skip to content

Commit

Permalink
Support configuring default namespace for kubectl/kustomize deployers
Browse files Browse the repository at this point in the history
  • Loading branch information
AndiDog committed Sep 16, 2020
1 parent 10275c6 commit f7e7b94
Show file tree
Hide file tree
Showing 22 changed files with 464 additions and 178 deletions.
3 changes: 3 additions & 0 deletions docs/content/en/docs/environment/templating.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ List of fields that support templating:
* `build.tagPolicy.envTemplate.template` (see [envTemplate tagger]({{< relref "/docs/pipeline-stages/taggers#envtemplate-using-values-of-environment-variables-as-tags)" >}}))
* `deploy.helm.releases.setValueTemplates` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
* `deploy.helm.releases.name` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
* `deploy.helm.releases.namespace` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
* `deploy.kubectl.defaultNamespace`
* `deploy.kustomize.defaultNamespace`

_Please note, this list is not exhaustive._

Expand Down
16 changes: 14 additions & 2 deletions docs/content/en/schemas/v2beta8.json
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,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`.",
Expand Down Expand Up @@ -1778,7 +1783,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.",
Expand Down Expand Up @@ -1841,6 +1847,11 @@
"x-intellij-html-description": "additional args passed to <code>kustomize build</code>.",
"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`.",
Expand All @@ -1859,7 +1870,8 @@
"preferredOrder": [
"paths",
"flags",
"buildArgs"
"buildArgs",
"defaultNamespace"
],
"additionalProperties": false,
"description": "*beta* uses the `kustomize` CLI to \"patch\" a deployment for a target environment.",
Expand Down
2 changes: 1 addition & 1 deletion integration/port_forward_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestPortForward(t *testing.T) {
Opts: config.SkaffoldOptions{
Namespace: ns.Name,
},
})
}, "")

logrus.SetLevel(logrus.TraceLevel)
portforward.SimulateDevCycle(t, kubectlCLI, ns.Name)
Expand Down
14 changes: 10 additions & 4 deletions integration/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

"github.com/GoogleContainerTools/skaffold/integration/skaffold"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
Expand Down Expand Up @@ -75,7 +76,7 @@ spec:
t.NewTempDir().
Write("deployment.yaml", test.input).
Chdir()
deployer := deploy.NewKubectlDeployer(&runcontext.RunContext{
deployer, err := deploy.NewKubectlDeployer(&runcontext.RunContext{
WorkingDir: ".",
Cfg: latest.Pipeline{
Deploy: latest.DeployConfig{
Expand All @@ -87,8 +88,9 @@ spec:
},
},
}, nil)
t.RequireNoError(err)
var b bytes.Buffer
err := deployer.Render(context.Background(), &b, test.builds, false, test.renderPath)
err = deployer.Render(context.Background(), &b, test.builds, false, test.renderPath)

t.CheckNoError(err)
dat, err := ioutil.ReadFile(test.renderPath)
Expand Down Expand Up @@ -229,7 +231,7 @@ spec:
Write("deployment.yaml", test.input).
Chdir()

deployer := deploy.NewKubectlDeployer(&runcontext.RunContext{
deployer, err := deploy.NewKubectlDeployer(&runcontext.RunContext{
WorkingDir: ".",
Cfg: latest.Pipeline{
Deploy: latest.DeployConfig{
Expand All @@ -240,9 +242,13 @@ spec:
},
},
},
Opts: config.SkaffoldOptions{
AddSkaffoldLabels: true,
},
}, nil)
t.RequireNoError(err)
var b bytes.Buffer
err := deployer.Render(context.Background(), &b, test.builds, false, "")
err = deployer.Render(context.Background(), &b, test.builds, false, "")

t.CheckNoError(err)
t.CheckDeepEqual(test.expectedOut, b.String())
Expand Down
2 changes: 1 addition & 1 deletion pkg/skaffold/build/cluster/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func NewBuilder(cfg Config) (*Builder, error) {

return &Builder{
ClusterDetails: cfg.Pipeline().Build.Cluster,
kubectlcli: kubectl.NewCLI(cfg),
kubectlcli: kubectl.NewCLI(cfg, ""),
timeout: timeout,
kubeContext: cfg.GetKubeContext(),
insecureRegistries: cfg.GetInsecureRegistries(),
Expand Down
26 changes: 22 additions & 4 deletions pkg/skaffold/deploy/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,13 @@ func (h *HelmDeployer) Deploy(ctx context.Context, out io.Writer, builds []build

// collect namespaces
for _, r := range results {
if trimmed := strings.TrimSpace(r.Namespace); trimmed != "" {
var namespace string
namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
if err != nil {
return nil, fmt.Errorf("cannot parse the release namespace template: %w", err)
}

if trimmed := strings.TrimSpace(namespace); trimmed != "" {
nsMap[trimmed] = struct{}{}
}
}
Expand Down Expand Up @@ -223,7 +229,10 @@ func (h *HelmDeployer) Cleanup(ctx context.Context, out io.Writer) error {
if h.namespace != "" {
namespace = h.namespace
} else if r.Namespace != "" {
namespace = r.Namespace
namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
if err != nil {
return fmt.Errorf("cannot parse the release namespace template: %w", err)
}
}

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

if r.Namespace != "" {
args = append(args, "--namespace", r.Namespace)
var namespace string
namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
if err != nil {
return fmt.Errorf("cannot parse the release namespace template: %w", err)
}

args = append(args, "--namespace", namespace)
}

outBuffer := new(bytes.Buffer)
Expand Down Expand Up @@ -340,7 +355,10 @@ func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r lates
if h.namespace != "" {
opts.namespace = h.namespace
} else if r.Namespace != "" {
opts.namespace = r.Namespace
opts.namespace, err = util.ExpandEnvTemplate(r.Namespace, nil)
if err != nil {
return nil, fmt.Errorf("cannot parse the release namespace template: %w", err)
}
}

if err := h.exec(ctx, ioutil.Discard, false, getArgs(helmVersion, releaseName, opts.namespace)...); err != nil {
Expand Down
65 changes: 64 additions & 1 deletion pkg/skaffold/deploy/helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ var testDeployNamespacedConfig = latest.HelmDeploy{
}},
}

var testDeployEnvTemplateNamespacedConfig = latest.HelmDeploy{
Releases: []latest.HelmRelease{{
Name: "skaffold-helm",
ChartPath: "examples/test",
ArtifactOverrides: map[string]string{
"image": "skaffold-helm",
},
Overrides: schemautil.HelmOverrides{Values: map[string]interface{}{"foo": "bar"}},
SetValues: map[string]string{
"some.key": "somevalue",
},
Namespace: "testRelease{{.FOO}}Namespace",
}},
}

var testDeployConfigTemplated = latest.HelmDeploy{
Releases: []latest.HelmRelease{{
Name: "skaffold-helm",
Expand Down Expand Up @@ -293,6 +308,7 @@ var testDeployCreateNamespaceConfig = latest.HelmDeploy{
}

var testNamespace = "testNamespace"
var testNamespace2 = "testNamespace2"

var validDeployYaml = `
# Source: skaffold-helm/templates/deployment.yaml
Expand Down Expand Up @@ -435,6 +451,7 @@ func TestHelmDeploy(t *testing.T) {
force bool
shouldErr bool
expectedWarnings []string
envs map[string]string
}{
{
description: "deploy success",
Expand Down Expand Up @@ -492,6 +509,17 @@ func TestHelmDeploy(t *testing.T) {
helm: testDeployNamespacedConfig,
builds: testBuilds,
},
{
description: "helm3.0 namespaced (with env template) deploy success",
commands: testutil.
CmdRunWithOutput("helm version --client", version30).
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig").
AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
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").
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig"),
helm: testDeployEnvTemplateNamespacedConfig,
builds: testBuilds,
},
{
description: "helm3.0 namespaced context deploy success",
commands: testutil.
Expand Down Expand Up @@ -538,6 +566,17 @@ func TestHelmDeploy(t *testing.T) {
helm: testDeployNamespacedConfig,
builds: testBuilds,
},
{
description: "helm3.1 namespaced deploy (with env template) success",
commands: testutil.
CmdRunWithOutput("helm version --client", version31).
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig").
AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
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").
AndRun("helm --kube-context kubecontext get all --namespace testReleaseFOOBARNamespace skaffold-helm --kubeconfig kubeconfig"),
helm: testDeployEnvTemplateNamespacedConfig,
builds: testBuilds,
},
{
description: "helm3.1 namespaced context deploy success",
commands: testutil.
Expand Down Expand Up @@ -908,6 +947,7 @@ func TestHelmCleanup(t *testing.T) {
builds []build.Artifact
shouldErr bool
expectedWarnings []string
envs map[string]string
}{
{
description: "cleanup success",
Expand All @@ -933,6 +973,14 @@ func TestHelmCleanup(t *testing.T) {
helm: testDeployNamespacedConfig,
builds: testBuilds,
},
{
description: "helm3 namespace (with env template) cleanup success",
commands: testutil.
CmdRunWithOutput("helm version --client", version31).
AndRun("helm --kube-context kubecontext delete skaffold-helm --namespace testReleaseFOOBARNamespace --kubeconfig kubeconfig"),
helm: testDeployEnvTemplateNamespacedConfig,
builds: testBuilds,
},
{
description: "helm3 namespaced context cleanup success",
commands: testutil.
Expand Down Expand Up @@ -1163,6 +1211,7 @@ func TestHelmRender(t *testing.T) {
outputFile string
expected string
builds []build.Artifact
envs map[string]string
}{
{
description: "error if version can't be retrieved",
Expand Down Expand Up @@ -1217,7 +1266,7 @@ func TestHelmRender(t *testing.T) {
shouldErr: false,
commands: testutil.
CmdRunWithOutput("helm version --client", version31).
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"),
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"),
helm: testDeployConfigTemplated,
builds: []build.Artifact{
{
Expand All @@ -1237,6 +1286,18 @@ func TestHelmRender(t *testing.T) {
Tag: "skaffold-helm:tag1",
}},
},
{
description: "render with namespace",
shouldErr: false,
commands: testutil.CmdRunWithOutput("helm version --client", version31).
AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --set-string image=skaffold-helm:tag1 --set some.key=somevalue --namespace testReleaseFOOBARNamespace --kubeconfig kubeconfig"),
helm: testDeployEnvTemplateNamespacedConfig,
builds: []build.Artifact{
{
ImageName: "skaffold-helm",
Tag: "skaffold-helm:tag1",
}},
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
Expand All @@ -1245,6 +1306,8 @@ func TestHelmRender(t *testing.T) {
file = t.NewTempDir().Path(test.outputFile)
}

t.Override(&util.OSEnviron, func() []string { return []string{"FOO=FOOBAR"} })

deployer := NewHelmDeployer(&helmConfig{
helm: test.helm,
}, nil)
Expand Down
15 changes: 12 additions & 3 deletions pkg/skaffold/deploy/kubectl.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,26 @@ type Config interface {

// NewKubectlDeployer returns a new KubectlDeployer for a DeployConfig filled
// with the needed configuration for `kubectl apply`
func NewKubectlDeployer(cfg Config, labels map[string]string) *KubectlDeployer {
func NewKubectlDeployer(cfg Config, labels map[string]string) (*KubectlDeployer, error) {
defaultNamespace := ""
if cfg.Pipeline().Deploy.KubectlDeploy.DefaultNamespace != nil {
var err error
defaultNamespace, err = util.ExpandEnvTemplate(*cfg.Pipeline().Deploy.KubectlDeploy.DefaultNamespace, nil)
if err != nil {
return nil, err
}
}

return &KubectlDeployer{
KubectlDeploy: cfg.Pipeline().Deploy.KubectlDeploy,
workingDir: cfg.GetWorkingDir(),
globalConfig: cfg.GlobalConfig(),
defaultRepo: cfg.DefaultRepo(),
kubectl: deploy.NewCLI(cfg, cfg.Pipeline().Deploy.KubectlDeploy.Flags),
kubectl: deploy.NewCLI(cfg, cfg.Pipeline().Deploy.KubectlDeploy.Flags, defaultNamespace),
insecureRegistries: cfg.GetInsecureRegistries(),
skipRender: cfg.SkipRender(),
labels: labels,
}
}, nil
}

// Deploy templates the provided manifests with a simple `find and replace` and
Expand Down
4 changes: 2 additions & 2 deletions pkg/skaffold/deploy/kubectl/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ type Config interface {
WaitForDeletions() config.WaitForDeletions
}

func NewCLI(cfg Config, flags latest.KubectlFlags) CLI {
func NewCLI(cfg Config, flags latest.KubectlFlags, defaultNameSpace string) CLI {
return CLI{
CLI: pkgkubectl.NewCLI(cfg),
CLI: pkgkubectl.NewCLI(cfg, defaultNameSpace),
Flags: flags,
forceDeploy: cfg.ForceDeploy(),
waitForDeletions: cfg.WaitForDeletions(),
Expand Down

0 comments on commit f7e7b94

Please sign in to comment.