From 75f67ffa6edade0a8acd8248a9fe21368362452b Mon Sep 17 00:00:00 2001 From: faizanahmad055 Date: Thu, 31 Jan 2019 16:03:53 +0100 Subject: [PATCH 1/3] Add support for envFrom for autoUpdate Signed-off-by: faizanahmad055 --- deployments/kubernetes/manifests/rbac.yaml | 73 ---------------- internal/pkg/handler/upgrade.go | 14 +++- internal/pkg/handler/upgrade_test.go | 97 ++++++++++++++++++++-- internal/pkg/testutil/kube.go | 59 ++++++++++++- internal/pkg/util/config.go | 2 +- 5 files changed, 163 insertions(+), 82 deletions(-) delete mode 100644 deployments/kubernetes/manifests/rbac.yaml diff --git a/deployments/kubernetes/manifests/rbac.yaml b/deployments/kubernetes/manifests/rbac.yaml deleted file mode 100644 index 4476c637..00000000 --- a/deployments/kubernetes/manifests/rbac.yaml +++ /dev/null @@ -1,73 +0,0 @@ ---- -# Source: reloader/templates/rbac.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app: reloader - group: com.stakater.platform - provider: stakater - version: 0.0.18 - chart: "reloader-0.0.18" - release: "RELEASE-NAME" - heritage: "Tiller" - name: reloader ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - labels: - app: reloader - group: com.stakater.platform - provider: stakater - version: 0.0.18 - chart: "reloader-0.0.18" - release: "RELEASE-NAME" - heritage: "Tiller" - name: reloader-role - namespace: default -rules: - - apiGroups: - - "" - resources: - - secrets - - configmaps - verbs: - - list - - get - - watch - - apiGroups: - - "" - - "extensions" - - "apps" - resources: - - deployments - - daemonsets - - statefulsets - verbs: - - list - - get - - update - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - labels: - app: reloader - group: com.stakater.platform - provider: stakater - version: 0.0.18 - chart: "reloader-0.0.18" - release: "RELEASE-NAME" - heritage: "Tiller" - name: reloader-role-binding - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: reloader-role -subjects: - - kind: ServiceAccount - name: reloader - namespace: default diff --git a/internal/pkg/handler/upgrade.go b/internal/pkg/handler/upgrade.go index a1a883f9..eb13c0d5 100644 --- a/internal/pkg/handler/upgrade.go +++ b/internal/pkg/handler/upgrade.go @@ -9,7 +9,7 @@ import ( "github.com/stakater/Reloader/internal/pkg/constants" "github.com/stakater/Reloader/internal/pkg/util" "github.com/stakater/Reloader/pkg/kube" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/client-go/kubernetes" ) @@ -147,6 +147,18 @@ func getContainerToUpdate(volumes []v1.Volume, containers []v1.Container, envarP } } + // Get the container with referenced secret or configmap + for i := range containers { + envs := containers[i].EnvFrom + for j := range envs { + if envs[j].SecretRef != nil && envs[j].SecretRef.LocalObjectReference.Name == volumeName { + return &containers[i] + } else if envs[j].ConfigMapRef != nil && envs[j].ConfigMapRef.LocalObjectReference.Name == volumeName { + return &containers[i] + } + } + } + return nil } diff --git a/internal/pkg/handler/upgrade_test.go b/internal/pkg/handler/upgrade_test.go index 52f98645..84f1a63a 100644 --- a/internal/pkg/handler/upgrade_test.go +++ b/internal/pkg/handler/upgrade_test.go @@ -13,12 +13,14 @@ import ( ) var ( - client = testclient.NewSimpleClientset() - namespace = "test-handler-" + testutil.RandSeq(5) - configmapName = "testconfigmap-handler-" + testutil.RandSeq(5) - secretName = "testsecret-handler-" + testutil.RandSeq(5) - configmapWithEnvName = "testconfigmapWithEnv-handler-" + testutil.RandSeq(3) - secretWithEnvName = "testsecretWithEnv-handler-" + testutil.RandSeq(5) + client = testclient.NewSimpleClientset() + namespace = "test-handler-" + testutil.RandSeq(5) + configmapName = "testconfigmap-handler-" + testutil.RandSeq(5) + secretName = "testsecret-handler-" + testutil.RandSeq(5) + configmapWithEnvName = "testconfigmapWithEnv-handler-" + testutil.RandSeq(3) + configmapWithEnvFromName = "testconfigmapWithEnvFrom-handler-" + testutil.RandSeq(3) + secretWithEnvName = "testsecretWithEnv-handler-" + testutil.RandSeq(5) + secretWithEnvFromName = "testsecretWithEnvFrom-handler-" + testutil.RandSeq(5) ) func TestMain(m *testing.M) { @@ -63,6 +65,17 @@ func setup() { logrus.Errorf("Error in secret creation: %v", err) } + _, err = testutil.CreateConfigMap(client, namespace, configmapWithEnvFromName, "www.google.com") + if err != nil { + logrus.Errorf("Error in configmap creation: %v", err) + } + + // Creating secret + _, err = testutil.CreateSecret(client, namespace, secretWithEnvFromName, data) + if err != nil { + logrus.Errorf("Error in secret creation: %v", err) + } + // Creating Deployment with configmap _, err = testutil.CreateDeployment(client, configmapName, namespace, true) if err != nil { @@ -87,6 +100,18 @@ func setup() { logrus.Errorf("Error in Deployment with secret configmap as env var source creation: %v", err) } + // Creating Deployment with envFrom source as secret + _, err = testutil.CreateDeploymentWithEnvVarSource(client, configmapWithEnvFromName, namespace) + if err != nil { + logrus.Errorf("Error in Deployment with secret configmap as envFrom source creation: %v", err) + } + + // Creating Deployment with envFrom source as secret + _, err = testutil.CreateDeploymentWithEnvVarSource(client, secretWithEnvFromName, namespace) + if err != nil { + logrus.Errorf("Error in Deployment with secret configmap as envFrom source creation: %v", err) + } + // Creating DaemonSet with configmap _, err = testutil.CreateDaemonSet(client, configmapName, namespace, true) if err != nil { @@ -162,6 +187,18 @@ func teardown() { logrus.Errorf("Error while deleting deployment with secret as env var source %v", deploymentError) } + // Deleting Deployment with configmap as envFrom source + deploymentError = testutil.DeleteDeployment(client, namespace, configmapWithEnvFromName) + if deploymentError != nil { + logrus.Errorf("Error while deleting deployment with configmap as envFrom source %v", deploymentError) + } + + // Deleting Deployment with secret as envFrom source + deploymentError = testutil.DeleteDeployment(client, namespace, secretWithEnvFromName) + if deploymentError != nil { + logrus.Errorf("Error while deleting deployment with secret as envFrom source %v", deploymentError) + } + // Deleting DaemonSet with configmap daemonSetError := testutil.DeleteDaemonSet(client, namespace, configmapName) if daemonSetError != nil { @@ -234,6 +271,18 @@ func teardown() { logrus.Errorf("Error while deleting the secret used as env var source %v", err) } + // Deleting Configmap used as env var source + err = testutil.DeleteConfigMap(client, namespace, configmapWithEnvFromName) + if err != nil { + logrus.Errorf("Error while deleting the configmap used as env var source %v", err) + } + + // Deleting Secret used as env var source + err = testutil.DeleteSecret(client, namespace, secretWithEnvFromName) + if err != nil { + logrus.Errorf("Error while deleting the secret used as env var source %v", err) + } + // Deleting namespace testutil.DeleteNamespace(namespace, client) @@ -286,6 +335,24 @@ func TestRollingUpgradeForDeploymentWithConfigmapAsEnvVar(t *testing.T) { } } +func TestRollingUpgradeForDeploymentWithConfigmapAsEnvVarFrom(t *testing.T) { + shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapWithEnvFromName, "www.stakater.com") + config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapWithEnvFromName, shaData, constants.ReloaderAutoAnnotation) + deploymentFuncs := GetDeploymentRollingUpgradeFuncs() + + err := PerformRollingUpgrade(client, config, deploymentFuncs) + time.Sleep(5 * time.Second) + if err != nil { + t.Errorf("Rolling upgrade failed for Deployment with Configmap used as env var") + } + + logrus.Infof("Verifying deployment update") + updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs) + if !updated { + t.Errorf("Deployment was not updated") + } +} + func TestRollingUpgradeForDeploymentWithSecret(t *testing.T) { shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy") config := getConfigWithAnnotations(constants.SecretEnvVarPostfix, secretName, shaData, constants.SecretUpdateOnChangeAnnotation) @@ -322,6 +389,24 @@ func TestRollingUpgradeForDeploymentWithSecretAsEnvVar(t *testing.T) { } } +func TestRollingUpgradeForDeploymentWithSecretAsEnvVarFrom(t *testing.T) { + shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretWithEnvFromName, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy") + config := getConfigWithAnnotations(constants.SecretEnvVarPostfix, secretWithEnvFromName, shaData, constants.ReloaderAutoAnnotation) + deploymentFuncs := GetDeploymentRollingUpgradeFuncs() + + err := PerformRollingUpgrade(client, config, deploymentFuncs) + time.Sleep(5 * time.Second) + if err != nil { + t.Errorf("Rolling upgrade failed for Deployment with Secret") + } + + logrus.Infof("Verifying deployment update") + updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs) + if !updated { + t.Errorf("Deployment was not updated") + } +} + func TestRollingUpgradeForDaemonSetWithConfigmap(t *testing.T) { shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.facebook.com") config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapName, shaData, constants.ConfigmapUpdateOnChangeAnnotation) diff --git a/internal/pkg/testutil/kube.go b/internal/pkg/testutil/kube.go index 24591896..ea7dae02 100644 --- a/internal/pkg/testutil/kube.go +++ b/internal/pkg/testutil/kube.go @@ -14,7 +14,7 @@ import ( "github.com/stakater/Reloader/internal/pkg/util" "github.com/stakater/Reloader/pkg/kube" v1_beta1 "k8s.io/api/apps/v1beta1" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/api/extensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -121,6 +121,38 @@ func getPodTemplateSpecWithEnvVars(name string) v1.PodTemplateSpec { } } +func getPodTemplateSpecWithEnvVarSources(name string) v1.PodTemplateSpec { + return v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"secondLabel": "temp"}, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Image: "tutum/hello-world", + Name: name, + EnvFrom: []v1.EnvFromSource{ + { + ConfigMapRef: &v1.ConfigMapEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: name, + }, + }, + }, + { + SecretRef: &v1.SecretEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: name, + }, + }, + }, + }, + }, + }, + }, + } +} + func getPodTemplateSpecWithVolumes(name string) v1.PodTemplateSpec { return v1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ @@ -202,6 +234,20 @@ func GetDeploymentWithEnvVars(namespace string, deploymentName string) *v1beta1. } } +func GetDeploymentWithEnvVarSources(namespace string, deploymentName string) *v1beta1.Deployment { + replicaset := int32(1) + return &v1beta1.Deployment{ + ObjectMeta: getObjectMeta(namespace, deploymentName, true), + Spec: v1beta1.DeploymentSpec{ + Replicas: &replicaset, + Strategy: v1beta1.DeploymentStrategy{ + Type: v1beta1.RollingUpdateDeploymentStrategyType, + }, + Template: getPodTemplateSpecWithEnvVarSources(deploymentName), + }, + } +} + // GetDaemonSet provides daemonset for testing func GetDaemonSet(namespace string, daemonsetName string) *v1beta1.DaemonSet { return &v1beta1.DaemonSet{ @@ -365,6 +411,17 @@ func CreateDeployment(client kubernetes.Interface, deploymentName string, namesp return deployment, err } +// CreateDeploymentWithEnvVarSource creates a deployment in given namespace and returns the Deployment +func CreateDeploymentWithEnvVarSource(client kubernetes.Interface, deploymentName string, namespace string) (*v1beta1.Deployment, error) { + logrus.Infof("Creating Deployment") + deploymentClient := client.ExtensionsV1beta1().Deployments(namespace) + var deploymentObj *v1beta1.Deployment + deploymentObj = GetDeploymentWithEnvVarSources(namespace, deploymentName) + deployment, err := deploymentClient.Create(deploymentObj) + time.Sleep(10 * time.Second) + return deployment, err +} + // CreateDaemonSet creates a deployment in given namespace and returns the DaemonSet func CreateDaemonSet(client kubernetes.Interface, daemonsetName string, namespace string, volumeMount bool) (*v1beta1.DaemonSet, error) { logrus.Infof("Creating DaemonSet") diff --git a/internal/pkg/util/config.go b/internal/pkg/util/config.go index 1643b383..24ef407f 100644 --- a/internal/pkg/util/config.go +++ b/internal/pkg/util/config.go @@ -2,7 +2,7 @@ package util import ( "github.com/stakater/Reloader/internal/pkg/constants" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" ) //Config contains rolling upgrade configuration parameters From 333957d82ad94ee5d116903e6a840cce88678c4f Mon Sep 17 00:00:00 2001 From: faizanahmad055 Date: Thu, 31 Jan 2019 16:32:47 +0100 Subject: [PATCH 2/3] Implemented golang CI comment Signed-off-by: faizanahmad055 --- internal/pkg/testutil/kube.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/pkg/testutil/kube.go b/internal/pkg/testutil/kube.go index ea7dae02..8612235c 100644 --- a/internal/pkg/testutil/kube.go +++ b/internal/pkg/testutil/kube.go @@ -415,8 +415,7 @@ func CreateDeployment(client kubernetes.Interface, deploymentName string, namesp func CreateDeploymentWithEnvVarSource(client kubernetes.Interface, deploymentName string, namespace string) (*v1beta1.Deployment, error) { logrus.Infof("Creating Deployment") deploymentClient := client.ExtensionsV1beta1().Deployments(namespace) - var deploymentObj *v1beta1.Deployment - deploymentObj = GetDeploymentWithEnvVarSources(namespace, deploymentName) + deploymentObj := GetDeploymentWithEnvVarSources(namespace, deploymentName) deployment, err := deploymentClient.Create(deploymentObj) time.Sleep(10 * time.Second) return deployment, err From 95bd5e497fe3b9a464edcd1166d890228c984295 Mon Sep 17 00:00:00 2001 From: faizanahmad055 Date: Fri, 1 Feb 2019 12:06:18 +0100 Subject: [PATCH 3/3] Use single container loop for envs Signed-off-by: faizanahmad055 --- internal/pkg/handler/upgrade.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/internal/pkg/handler/upgrade.go b/internal/pkg/handler/upgrade.go index eb13c0d5..0d059111 100644 --- a/internal/pkg/handler/upgrade.go +++ b/internal/pkg/handler/upgrade.go @@ -132,7 +132,7 @@ func getContainerToUpdate(volumes []v1.Volume, containers []v1.Container, envarP } } - // Get the container with referenced secret or configmap + // Get the container with referenced secret or configmap as env var for i := range containers { envs := containers[i].Env for j := range envs { @@ -145,15 +145,12 @@ func getContainerToUpdate(volumes []v1.Volume, containers []v1.Container, envarP } } } - } - // Get the container with referenced secret or configmap - for i := range containers { - envs := containers[i].EnvFrom - for j := range envs { - if envs[j].SecretRef != nil && envs[j].SecretRef.LocalObjectReference.Name == volumeName { + envsFrom := containers[i].EnvFrom + for j := range envsFrom { + if envsFrom[j].SecretRef != nil && envsFrom[j].SecretRef.LocalObjectReference.Name == volumeName { return &containers[i] - } else if envs[j].ConfigMapRef != nil && envs[j].ConfigMapRef.LocalObjectReference.Name == volumeName { + } else if envsFrom[j].ConfigMapRef != nil && envsFrom[j].ConfigMapRef.LocalObjectReference.Name == volumeName { return &containers[i] } }