From f9c89f2d33833445e89187eaea7ae1a979a5aa17 Mon Sep 17 00:00:00 2001 From: Levi Blackstone Date: Tue, 9 Apr 2019 16:59:41 -0600 Subject: [PATCH] Fix Deployment await logic for old API schema (#523) Resources created with the old extensions/v1beta1:Deployment schema do not include two status fields that the await logic was expecting. Add an exception for this API version to make those checks pass. --- CHANGELOG.md | 1 + pkg/await/apps_deployment.go | 24 +++- pkg/await/apps_deployment_test.go | 66 +++++----- .../deployment_rollout_test.go | 120 ++++++++++++++++++ .../deployment-rollout/step1/Pulumi.yaml | 3 + .../deployment-rollout/step1/index.ts | 50 ++++++++ .../deployment-rollout/step1/package.json | 13 ++ .../deployment-rollout/step1/tsconfig.json | 22 ++++ .../deployment-rollout/step2/index.ts | 51 ++++++++ 9 files changed, 314 insertions(+), 36 deletions(-) create mode 100644 tests/integration/deployment-rollout/deployment_rollout_test.go create mode 100644 tests/integration/deployment-rollout/step1/Pulumi.yaml create mode 100644 tests/integration/deployment-rollout/step1/index.ts create mode 100644 tests/integration/deployment-rollout/step1/package.json create mode 100644 tests/integration/deployment-rollout/step1/tsconfig.json create mode 100644 tests/integration/deployment-rollout/step2/index.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index fdc8a5ddd3..54b86b8daa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ ### Bug fixes +- Fix Deployment await logic for old API schema (https://github.com/pulumi/pulumi-kubernetes/pull/523) - Replace PodDisruptionBudget if spec changes (https://github.com/pulumi/pulumi-kubernetes/pull/527) ## 0.22.0 (March 25, 2019) diff --git a/pkg/await/apps_deployment.go b/pkg/await/apps_deployment.go index 43f7136afe..f320c2775a 100644 --- a/pkg/await/apps_deployment.go +++ b/pkg/await/apps_deployment.go @@ -401,6 +401,9 @@ func (dia *deploymentInitAwaiter) processDeploymentEvent(event watch.Event) { return } + // extensions/v1beta1 does not include the "Progressing" status for rollouts. + progressingStatusUnavailable := dia.deployment.GetAPIVersion() == "extensions/v1beta1" + // Success occurs when the ReplicaSet of the `currentGeneration` is marked as available, and // when the deployment is available. for _, rawCondition := range conditions { @@ -409,7 +412,10 @@ func (dia *deploymentInitAwaiter) processDeploymentEvent(event watch.Event) { continue } - if condition["type"] == "Progressing" { + if progressingStatusUnavailable { + // Since we can't tell for sure from this version of the API, mark as available. + dia.replicaSetAvailable = true + } else if condition["type"] == "Progressing" { isProgressing := condition["status"] == trueStatus if !isProgressing { rawReason, hasReason := condition["reason"] @@ -511,8 +517,20 @@ func (dia *deploymentInitAwaiter) checkReplicaSetStatus() { if !specReplicasExists { specReplicas = 1 } - rawReadyReplicas, readyReplicasExists := openapi.Pluck(rs.Object, "status", "readyReplicas") - readyReplicas, _ := rawReadyReplicas.(int64) + + var rawReadyReplicas interface{} + var readyReplicas int64 + var readyReplicasExists bool + // extensions/v1beta1/ReplicaSet does not include the "readyReplicas" status for rollouts, + // so use the Deployment "readyReplicas" status instead. + statusUnavailable := dia.deployment.GetAPIVersion() == "extensions/v1beta1" + if statusUnavailable { + rawReadyReplicas, readyReplicasExists = openapi.Pluck(dia.deployment.Object, "status", "readyReplicas") + readyReplicas, _ = rawReadyReplicas.(int64) + } else { + rawReadyReplicas, readyReplicasExists = openapi.Pluck(rs.Object, "status", "readyReplicas") + readyReplicas, _ = rawReadyReplicas.(int64) + } glog.V(3).Infof("ReplicaSet %q requests '%v' replicas, but has '%v' ready", rs.GetName(), specReplicas, readyReplicas) diff --git a/pkg/await/apps_deployment_test.go b/pkg/await/apps_deployment_test.go index 91e5c112c4..0556314bfb 100644 --- a/pkg/await/apps_deployment_test.go +++ b/pkg/await/apps_deployment_test.go @@ -884,7 +884,7 @@ func Test_Core_Deployment_Read(t *testing.T) { func deploymentInput(namespace, name string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -925,7 +925,7 @@ func deploymentInput(namespace, name string) *unstructured.Unstructured { func deploymentAdded(namespace, name, revision string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -973,7 +973,7 @@ func deploymentAdded(namespace, name, revision string) *unstructured.Unstructure func deploymentProgressing(namespace, name, revision string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1031,7 +1031,7 @@ func deploymentProgressing(namespace, name, revision string) *unstructured.Unstr func deploymentNotProgressing(namespace, name, revision string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "generation": 3, @@ -1104,7 +1104,7 @@ func deploymentNotProgressing(namespace, name, revision string) *unstructured.Un func deploymentProgressingInvalidContainer(namespace, name, revision string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "generation": 4, @@ -1180,7 +1180,7 @@ func deploymentProgressingInvalidContainer(namespace, name, revision string) *un func deploymentProgressingUnavailable(namespace, name, revision string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1254,7 +1254,7 @@ func deploymentProgressingUnavailable(namespace, name, revision string) *unstruc func deploymentRevision1Created(namespace, name string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1320,7 +1320,7 @@ func deploymentRevision1Created(namespace, name string) *unstructured.Unstructur func deploymentRevision2Created(namespace, name string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1384,7 +1384,7 @@ func deploymentRevision2Created(namespace, name string) *unstructured.Unstructur func deploymentRolloutComplete(namespace, name, revision string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1456,7 +1456,7 @@ func deploymentRolloutComplete(namespace, name, revision string) *unstructured.U func deploymentUpdated(namespace, name, revision string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1528,7 +1528,7 @@ func deploymentUpdated(namespace, name, revision string) *unstructured.Unstructu func deploymentUpdatedReplicaSetProgressing(namespace, name, revision string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1600,7 +1600,7 @@ func deploymentUpdatedReplicaSetProgressing(namespace, name, revision string) *u func deploymentUpdatedReplicaSetProgressed(namespace, name, revision string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1677,7 +1677,7 @@ func deploymentUpdatedReplicaSetProgressed(namespace, name, revision string) *un func deploymentWithPVCAdded(namespace, name, revision, pvcName string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1739,7 +1739,7 @@ func deploymentWithPVCAdded(namespace, name, revision, pvcName string) *unstruct func deploymentWithPVCProgressing(namespace, name, revision, pvcName string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -1811,7 +1811,7 @@ func deploymentWithPVCProgressing(namespace, name, revision, pvcName string) *un func deploymentWithPVCNotProgressing(namespace, name, revision, pvcName string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "generation": 3, @@ -1899,7 +1899,7 @@ func deploymentWithPVCNotProgressing(namespace, name, revision, pvcName string) func deploymentWithPVCInput(namespace, name, pvcName string) *unstructured.Unstructured { obj, err := decodeUnstructured(fmt.Sprintf(`{ "kind": "Deployment", - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "metadata": { "namespace": "%s", "name": "%s", @@ -2025,7 +2025,7 @@ func persistentVolumeClaimPending(namespace, name string) *unstructured.Unstruct func regressionDeploymentScaled3Input() *unstructured.Unstructured { obj, err := decodeUnstructured(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "name": "frontend-ur1fwk62", @@ -2054,7 +2054,7 @@ func regressionDeploymentScaled3Input() *unstructured.Unstructured { func regressionDeploymentScaled3() *unstructured.Unstructured { obj, err := decodeUnstructured(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "annotations": { @@ -2069,7 +2069,7 @@ func regressionDeploymentScaled3() *unstructured.Unstructured { "name": "frontend-ur1fwk62", "namespace": "default", "resourceVersion": "917821", - "selfLink": "/apis/extensions/v1beta1/namespaces/default/deployments/frontend-ur1fwk62", + "selfLink": "/apis/apps/v1/namespaces/default/deployments/frontend-ur1fwk62", "uid": "e0a51d3c-a58c-11e8-8cb4-080027bd9056" }, "spec": { @@ -2166,7 +2166,7 @@ func regressionDeploymentScaled3() *unstructured.Unstructured { func regressionDeploymentScaled5() *unstructured.Unstructured { obj, err := decodeUnstructured(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "annotations": { @@ -2181,7 +2181,7 @@ func regressionDeploymentScaled5() *unstructured.Unstructured { "name": "frontend-ur1fwk62", "namespace": "default", "resourceVersion": "918077", - "selfLink": "/apis/extensions/v1beta1/namespaces/default/deployments/frontend-ur1fwk62", + "selfLink": "/apis/apps/v1/namespaces/default/deployments/frontend-ur1fwk62", "uid": "e0a51d3c-a58c-11e8-8cb4-080027bd9056" }, "spec": { @@ -2278,7 +2278,7 @@ func regressionDeploymentScaled5() *unstructured.Unstructured { func regressionReplicaSetScaled3() *unstructured.Unstructured { obj, err := decodeUnstructured(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "ReplicaSet", "metadata": { "annotations": { @@ -2297,7 +2297,7 @@ func regressionReplicaSetScaled3() *unstructured.Unstructured { "namespace": "default", "ownerReferences": [ { - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "blockOwnerDeletion": true, "controller": true, "kind": "Deployment", @@ -2306,7 +2306,7 @@ func regressionReplicaSetScaled3() *unstructured.Unstructured { } ], "resourceVersion": "924664", - "selfLink": "/apis/extensions/v1beta1/namespaces/default/replicasets/frontend-ur1fwk62-777d669468", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/frontend-ur1fwk62-777d669468", "uid": "ef9a880f-a599-11e8-8cb4-080027bd9056" }, "spec": { @@ -2377,7 +2377,7 @@ func regressionReplicaSetScaled3() *unstructured.Unstructured { func regressionReplicaSetScaled5() *unstructured.Unstructured { obj, err := decodeUnstructured(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "ReplicaSet", "metadata": { "annotations": { @@ -2396,7 +2396,7 @@ func regressionReplicaSetScaled5() *unstructured.Unstructured { "namespace": "default", "ownerReferences": [ { - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "blockOwnerDeletion": true, "controller": true, "kind": "Deployment", @@ -2405,7 +2405,7 @@ func regressionReplicaSetScaled5() *unstructured.Unstructured { } ], "resourceVersion": "918076", - "selfLink": "/apis/extensions/v1beta1/namespaces/default/replicasets/frontend-ur1fwk62-777d669468", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/frontend-ur1fwk62-777d669468", "uid": "e0a588b0-a58c-11e8-8cb4-080027bd9056" }, "spec": { @@ -2483,7 +2483,7 @@ func regressionReplicaSetScaled5() *unstructured.Unstructured { func availableReplicaSet(namespace, name, deploymentName, revision string) *unstructured.Unstructured { // nolint obj, err := decodeUnstructured(fmt.Sprintf(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "ReplicaSet", "metadata": { "annotations": { @@ -2504,7 +2504,7 @@ func availableReplicaSet(namespace, name, deploymentName, revision string) *unst "name": "%s", "ownerReferences": [ { - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "blockOwnerDeletion": true, "controller": true, "kind": "Deployment", @@ -2581,7 +2581,7 @@ func availableReplicaSet(namespace, name, deploymentName, revision string) *unst func availableReplicaSetWithPVC(namespace, name, deploymentName, revision, pvcName string) *unstructured.Unstructured { // nolint obj, err := decodeUnstructured(fmt.Sprintf(`{ - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "kind": "ReplicaSet", "metadata": { "annotations": { @@ -2602,7 +2602,7 @@ func availableReplicaSetWithPVC(namespace, name, deploymentName, revision, pvcNa "name": "%s", "ownerReferences": [ { - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "blockOwnerDeletion": true, "controller": true, "kind": "Deployment", @@ -2700,7 +2700,7 @@ func deployedReadyPod(namespace, name, replicaSetName string) *unstructured.Unst "name": "%s", "ownerReferences": [ { - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "blockOwnerDeletion": true, "controller": true, "kind": "ReplicaSet", @@ -2826,7 +2826,7 @@ func deployedFailedPod(namespace, name, replicaSetName string) *unstructured.Uns "name": "%s", "ownerReferences": [ { - "apiVersion": "extensions/v1beta1", + "apiVersion": "apps/v1", "blockOwnerDeletion": true, "controller": true, "kind": "ReplicaSet", diff --git a/tests/integration/deployment-rollout/deployment_rollout_test.go b/tests/integration/deployment-rollout/deployment_rollout_test.go new file mode 100644 index 0000000000..265ba1a1f9 --- /dev/null +++ b/tests/integration/deployment-rollout/deployment_rollout_test.go @@ -0,0 +1,120 @@ +// Copyright 2016-2019, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ints + +import ( + "os" + "strings" + "testing" + + "github.com/pulumi/pulumi/pkg/tokens" + + "github.com/pulumi/pulumi-kubernetes/pkg/openapi" + "github.com/pulumi/pulumi-kubernetes/tests" + "github.com/pulumi/pulumi/pkg/resource" + "github.com/pulumi/pulumi/pkg/resource/deploy/providers" + "github.com/pulumi/pulumi/pkg/testing/integration" + "github.com/stretchr/testify/assert" +) + +func TestDeploymentRollout(t *testing.T) { + kubectx := os.Getenv("KUBERNETES_CONTEXT") + + if kubectx == "" { + t.Skipf("Skipping test due to missing KUBERNETES_CONTEXT variable") + } + + integration.ProgramTest(t, &integration.ProgramTestOptions{ + Dir: "step1", + Dependencies: []string{"@pulumi/kubernetes"}, + Quick: true, + ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { + assert.NotNil(t, stackInfo.Deployment) + assert.Equal(t, 5, len(stackInfo.Deployment.Resources)) + + tests.SortResourcesByURN(stackInfo) + + appsv1Deploy := stackInfo.Deployment.Resources[0] + namespace := stackInfo.Deployment.Resources[1] + extensionsv1beta1Deploy := stackInfo.Deployment.Resources[2] + provRes := stackInfo.Deployment.Resources[3] + stackRes := stackInfo.Deployment.Resources[4] + + assert.Equal(t, resource.RootStackType, stackRes.URN.Type()) + assert.True(t, providers.IsProviderType(provRes.URN.Type())) + + assert.Equal(t, tokens.Type("kubernetes:core/v1:Namespace"), namespace.URN.Type()) + + // + // Assert deployments are successfully created. + // + + name, _ := openapi.Pluck(appsv1Deploy.Outputs, "metadata", "name") + assert.True(t, strings.Contains(name.(string), "nginx")) + containers, _ := openapi.Pluck(appsv1Deploy.Outputs, "spec", "template", "spec", "containers") + containerStatus := containers.([]interface{})[0].(map[string]interface{}) + image := containerStatus["image"] + assert.Equal(t, image.(string), "nginx") + + name, _ = openapi.Pluck(extensionsv1beta1Deploy.Outputs, "metadata", "name") + assert.True(t, strings.Contains(name.(string), "nginx")) + containers, _ = openapi.Pluck(appsv1Deploy.Outputs, "spec", "template", "spec", "containers") + containerStatus = containers.([]interface{})[0].(map[string]interface{}) + image = containerStatus["image"] + assert.Equal(t, image.(string), "nginx") + }, + EditDirs: []integration.EditDir{ + { + Dir: "step2", + Additive: true, + ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { + assert.NotNil(t, stackInfo.Deployment) + assert.Equal(t, 5, len(stackInfo.Deployment.Resources)) + + tests.SortResourcesByURN(stackInfo) + + appsv1Deploy := stackInfo.Deployment.Resources[0] + namespace := stackInfo.Deployment.Resources[1] + extensionsv1beta1Deploy := stackInfo.Deployment.Resources[2] + provRes := stackInfo.Deployment.Resources[3] + stackRes := stackInfo.Deployment.Resources[4] + + assert.Equal(t, resource.RootStackType, stackRes.URN.Type()) + assert.True(t, providers.IsProviderType(provRes.URN.Type())) + + assert.Equal(t, tokens.Type("kubernetes:core/v1:Namespace"), namespace.URN.Type()) + + // + // Assert deployments are updated successfully. + // + + name, _ := openapi.Pluck(appsv1Deploy.Outputs, "metadata", "name") + assert.True(t, strings.Contains(name.(string), "nginx")) + containers, _ := openapi.Pluck(appsv1Deploy.Outputs, "spec", "template", "spec", "containers") + containerStatus := containers.([]interface{})[0].(map[string]interface{}) + image := containerStatus["image"] + assert.Equal(t, image.(string), "nginx:stable") + + name, _ = openapi.Pluck(extensionsv1beta1Deploy.Outputs, "metadata", "name") + assert.True(t, strings.Contains(name.(string), "nginx")) + containers, _ = openapi.Pluck(appsv1Deploy.Outputs, "spec", "template", "spec", "containers") + containerStatus = containers.([]interface{})[0].(map[string]interface{}) + image = containerStatus["image"] + assert.Equal(t, image.(string), "nginx:stable") + }, + }, + }, + }) +} diff --git a/tests/integration/deployment-rollout/step1/Pulumi.yaml b/tests/integration/deployment-rollout/step1/Pulumi.yaml new file mode 100644 index 0000000000..0889c62257 --- /dev/null +++ b/tests/integration/deployment-rollout/step1/Pulumi.yaml @@ -0,0 +1,3 @@ +name: deployment-rollout +description: A program that tests Deployment rollouts. +runtime: nodejs diff --git a/tests/integration/deployment-rollout/step1/index.ts b/tests/integration/deployment-rollout/step1/index.ts new file mode 100644 index 0000000000..32e6b9a17c --- /dev/null +++ b/tests/integration/deployment-rollout/step1/index.ts @@ -0,0 +1,50 @@ +// Copyright 2016-2019, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as k8s from "@pulumi/kubernetes"; + +export const namespace = new k8s.core.v1.Namespace("test-namespace"); + +// +// Create an extensions/v1beta1 Deployment. +// + +const appLabels = {app: "nginx"}; +new k8s.extensions.v1beta1.Deployment("nginx", { + metadata: { namespace: namespace.metadata.name }, + spec: { + selector: {matchLabels: appLabels}, + replicas: 1, + template: { + metadata: {labels: appLabels}, + spec: {containers: [{name: "nginx", image: "nginx", ports: [{containerPort: 80}]}]} + } + } +}); + +// +// Create an apps/v1 Deployment. +// + +new k8s.apps.v1.Deployment("nginx", { + metadata: { namespace: namespace.metadata.name }, + spec: { + selector: {matchLabels: appLabels}, + replicas: 1, + template: { + metadata: {labels: appLabels}, + spec: {containers: [{name: "nginx", image: "nginx", ports: [{containerPort: 80}]}]} + } + } +}); diff --git a/tests/integration/deployment-rollout/step1/package.json b/tests/integration/deployment-rollout/step1/package.json new file mode 100644 index 0000000000..461d435ce4 --- /dev/null +++ b/tests/integration/deployment-rollout/step1/package.json @@ -0,0 +1,13 @@ +{ + "name": "steps", + "version": "0.1.0", + "dependencies": { + "@pulumi/pulumi": "dev" + }, + "devDependencies": { + "typescript": "^3.0.0" + }, + "peerDependencies": { + "@pulumi/kubernetes": "latest" + } +} diff --git a/tests/integration/deployment-rollout/step1/tsconfig.json b/tests/integration/deployment-rollout/step1/tsconfig.json new file mode 100644 index 0000000000..5dacccbd42 --- /dev/null +++ b/tests/integration/deployment-rollout/step1/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "outDir": "bin", + "target": "es6", + "module": "commonjs", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "stripInternal": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true, + "strictNullChecks": true + }, + "files": [ + "index.ts" + ] +} + diff --git a/tests/integration/deployment-rollout/step2/index.ts b/tests/integration/deployment-rollout/step2/index.ts new file mode 100644 index 0000000000..9a38be0334 --- /dev/null +++ b/tests/integration/deployment-rollout/step2/index.ts @@ -0,0 +1,51 @@ +// Copyright 2016-2019, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as k8s from "@pulumi/kubernetes"; + +export const namespace = new k8s.core.v1.Namespace("test-namespace"); + +// +// Change the image to trigger an update. +// + +const appLabels = {app: "nginx"}; +new k8s.extensions.v1beta1.Deployment("nginx", { + metadata: { namespace: namespace.metadata.name }, + spec: { + selector: {matchLabels: appLabels}, + replicas: 1, + template: { + metadata: {labels: appLabels}, + spec: {containers: [{name: "nginx", image: "nginx:stable", ports: [{containerPort: 80}]}]} + } + } +}); + +// +// Change the image to trigger an update. +// + +new k8s.apps.v1.Deployment("nginx", { + metadata: { namespace: namespace.metadata.name }, + spec: { + selector: {matchLabels: appLabels}, + replicas: 1, + template: { + metadata: {labels: appLabels}, + spec: {containers: [{name: "nginx", image: "nginx:stable", ports: [{containerPort: 80}]}]} + } + } +}); +