Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support configuring default namespace for kubectl/kustomize deployers #4374

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading