Add handler testcases

This commit is contained in:
faizanahmad055
2018-07-19 18:04:07 +05:00
parent f89f59c5b2
commit 17b6d58300
4 changed files with 628 additions and 211 deletions
+24 -184
View File
@@ -1,37 +1,22 @@
package controller
import (
"math/rand"
"strings"
"testing"
"time"
"github.com/sirupsen/logrus"
helper "github.com/stakater/Reloader/internal/pkg/helper"
"github.com/stakater/Reloader/pkg/kube"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
var (
configmapNamePrefix = "testconfigmap-reloader"
secretNamePrefix = "testsecret-reloader"
letters = []rune("abcdefghijklmnopqrstuvwxyz")
configmapUpdateOnChangeAnnotation = "reloader.stakater.com/configmap.update-on-change"
secretUpdateOnChangeAnnotation = "reloader.stakater.com/secret.update-on-change"
configmapNamePrefix = "testconfigmap-reloader"
secretNamePrefix = "testsecret-reloader"
)
func randSeq(n int) string {
rand.Seed(time.Now().UnixNano())
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
// Creating a Controller to do a rolling upgrade upon updating the configmap or secret
func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
client, err := kube.GetClient()
@@ -41,8 +26,8 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
}
namespace := "test-reloader"
logrus.Infof("Step 1: Create namespace")
createNamespace(t, namespace, client)
defer deleteNamespace(t, namespace, client)
helper.CreateNamespace(namespace, client)
defer helper.DeleteNamespace(namespace, client)
logrus.Infof("Step 2: Create controller")
controller, err := NewController(client, "configMaps", namespace)
@@ -56,13 +41,13 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
go controller.Run(1, stop)
time.Sleep(10 * time.Second)
configmapName := configmapNamePrefix + "-update-" + randSeq(5)
configmapName := configmapNamePrefix + "-update-" + helper.RandSeq(5)
configmapClient := client.CoreV1().ConfigMaps(namespace)
logrus.Infof("Step 4: Create configmap")
_, err = configmapClient.Create(initConfigmap(namespace, configmapName))
_, err = configmapClient.Create(helper.GetConfigmap(namespace, configmapName, "www.google.com"))
if err != nil {
logrus.Fatalf("Fatal error in configmap creation: %v", err)
t.Errorf("Error in configmap creation: %v", err)
}
logrus.Infof("Created Configmap %q.\n", configmapName)
time.Sleep(10 * time.Second)
@@ -76,7 +61,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
if err != nil {
logrus.Errorf("Error while getting configmap %v", err)
}
_, updateErr := configmapClient.Update(updateConfigmap(namespace, configmapName, "www.stakater.com"))
_, updateErr := configmapClient.Update(helper.GetConfigmap(namespace, configmapName, "www.stakater.com"))
if updateErr != nil {
err = controller.client.CoreV1().ConfigMaps(namespace).Delete(configmapName, &metav1.DeleteOptions{})
@@ -88,19 +73,20 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
time.Sleep(10 * time.Second)
logrus.Infof("Step 7: Verify deployment update for first time")
updated := verifyDeploymentUpdate(client, namespace, configmapName, "_CONFIGMAP", "www.stakater.com")
shaData := helper.ConvertConfigmapToSHA(helper.GetConfigmap(namespace, configmapName, "www.stakater.com"))
updated := helper.VerifyDeploymentUpdate(client, namespace, configmapName, "_CONFIGMAP", shaData)
if !updated {
t.Errorf("Deployment was not updated")
}
time.Sleep(10 * time.Second)
logrus.Infof("Step 8: Update configmap for Second time")
_, updateErr = configmapClient.Update(updateConfigmap(namespace, configmapName, "aurorasolutions.io"))
_, updateErr = configmapClient.Update(helper.GetConfigmap(namespace, configmapName, "aurorasolutions.io"))
time.Sleep(10 * time.Second)
logrus.Infof("Step 9: Verify deployment update for second time")
updated = verifyDeploymentUpdate(client, namespace, configmapName, "_CONFIGMAP", "aurorasolutions.io")
shaData = helper.ConvertConfigmapToSHA(helper.GetConfigmap(namespace, configmapName, "aurorasolutions.io"))
updated = helper.VerifyDeploymentUpdate(client, namespace, configmapName, "_CONFIGMAP", shaData)
if !updated {
t.Errorf("Deployment was not updated")
}
@@ -110,7 +96,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
logrus.Infof("Deleting Deployment %q.\n", deployment.GetObjectMeta().GetName())
deploymentError := controller.client.ExtensionsV1beta1().Deployments(namespace).Delete(configmapName, &metav1.DeleteOptions{})
if deploymentError != nil {
logrus.Fatalf("Error while deleting the configmap %v", deploymentError)
logrus.Errorf("Error while deleting the configmap %v", deploymentError)
}
logrus.Infof("Step 11: Delete Configmap")
@@ -122,60 +108,12 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
time.Sleep(15 * time.Second)
}
func verifyDeploymentUpdate(client kubernetes.Interface, namespace string, name string, resourceType string, change string) bool {
deployments, err := client.ExtensionsV1beta1().Deployments(namespace).List(metav1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list deployments %v", err)
}
for _, d := range deployments.Items {
containers := d.Spec.Template.Spec.Containers
// match deployments with the correct annotation
annotationValue := d.ObjectMeta.Annotations[configmapUpdateOnChangeAnnotation]
if annotationValue != "" {
values := strings.Split(annotationValue, ",")
matches := false
for _, value := range values {
if value == name {
matches = true
break
}
}
if matches {
sshData := helper.ConvertConfigmapToSHA(updateConfigmap(namespace, name, change))
envName := "STAKATER_" + helper.ConvertToEnvVarName(annotationValue) + resourceType
updated := getResourceSsh(containers, envName)
logrus.Infof("sshData %s", sshData)
logrus.Infof("updated %s", updated)
if updated != sshData {
return false
} else {
return true
}
}
}
}
return false
}
func getResourceSsh(containers []v1.Container, envar string) string {
for i := range containers {
envs := containers[i].Env
for j := range envs {
if envs[j].Name == envar {
return envs[j].Value
}
}
}
return ""
}
func createDeployment(deploymentName string, namespace string, client kubernetes.Interface) *v1beta1.Deployment {
deploymentClient := client.ExtensionsV1beta1().Deployments(namespace)
deployment := initDeployment(namespace, deploymentName)
deployment := helper.GetDeployment(namespace, deploymentName)
deployment, err := deploymentClient.Create(deployment)
if err != nil {
logrus.Fatalf("Fatal error in deployment creation: %v", err)
logrus.Errorf("Error in deployment creation: %v", err)
}
logrus.Infof("Created Deployment %q.\n", deployment.GetObjectMeta().GetName())
return deployment
@@ -188,8 +126,8 @@ func TestControllerForUpdatingSecretShouldUpdateDeployment(t *testing.T) {
return
}
namespace := "test-reloader-secrets"
createNamespace(t, namespace, client)
defer deleteNamespace(t, namespace, client)
helper.CreateNamespace(namespace, client)
defer helper.DeleteNamespace(namespace, client)
controller, err := NewController(client, "secrets", namespace)
if err != nil {
@@ -201,11 +139,12 @@ func TestControllerForUpdatingSecretShouldUpdateDeployment(t *testing.T) {
go controller.Run(1, stop)
time.Sleep(10 * time.Second)
secretName := secretNamePrefix + "-update-" + randSeq(5)
secretName := secretNamePrefix + "-update-" + helper.RandSeq(5)
secretClient := client.CoreV1().Secrets(namespace)
_, err = secretClient.Create(initSecret(namespace, secretName))
data := "dGVzdFNlY3JldEVuY29kaW5nRm9yUmVsb2FkZXI="
_, err = secretClient.Create(helper.GetSecret(namespace, secretName, data))
if err != nil {
logrus.Fatalf("Fatal error in secret creation: %v", err)
logrus.Errorf("Error in secret creation: %v", err)
}
logrus.Infof("Created Secret %q.\n", secretName)
time.Sleep(10 * time.Second)
@@ -215,7 +154,8 @@ func TestControllerForUpdatingSecretShouldUpdateDeployment(t *testing.T) {
if err != nil {
logrus.Errorf("Error while getting secret %v", err)
}
_, updateErr := secretClient.Update(updateSecret(namespace, secretName))
data = "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy"
_, updateErr := secretClient.Update(helper.GetSecret(namespace, secretName, data))
// TODO: Add functionality to verify reloader functionality here
@@ -234,103 +174,3 @@ func TestControllerForUpdatingSecretShouldUpdateDeployment(t *testing.T) {
}
time.Sleep(15 * time.Second)
}
func initConfigmap(namespace string, configmapName string) *v1.ConfigMap {
return &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: configmapName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
},
Data: map[string]string{"test.url": "www.google.com"},
}
}
func initDeployment(namespace string, deploymentName string) *v1beta1.Deployment {
replicaset := int32(1)
return &v1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: deploymentName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
Annotations: map[string]string{"reloader.stakater.com/configmap.update-on-change": deploymentName},
},
Spec: v1beta1.DeploymentSpec{
Replicas: &replicaset,
Strategy: v1beta1.DeploymentStrategy{
Type: v1beta1.RollingUpdateDeploymentStrategyType,
},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"secondLabel": "temp"},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Image: "tutum/hello-world",
Name: deploymentName,
Env: []v1.EnvVar{
{
Name: "BUCKET_NAME",
Value: "test",
},
},
},
},
},
},
},
}
}
func initSecret(namespace string, secretName string) *v1.Secret {
return &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
},
Data: map[string][]byte{"test.url": []byte("dGVzdFNlY3JldEVuY29kaW5nRm9yUmVsb2FkZXI=")},
}
}
func createNamespace(t *testing.T, namespace string, client kubernetes.Interface) {
_, err := client.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}})
if err != nil {
t.Error("Failed to create namespace for testing", err)
} else {
logrus.Infof("Creating namespace for testing = %s", namespace)
}
}
func deleteNamespace(t *testing.T, namespace string, client kubernetes.Interface) {
logrus.Infof("Step 12: Delete Namespace")
err := client.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{})
if err != nil {
t.Error("Failed to delete namespace that was created for testing", err)
} else {
logrus.Infof("Deleting namespace for testing = %s", namespace)
}
}
func updateConfigmap(namespace string, configmapName string, testData string) *v1.ConfigMap {
return &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: configmapName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
},
Data: map[string]string{"test.url": testData},
}
}
func updateSecret(namespace string, secretName string) *v1.Secret {
return &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
},
Data: map[string][]byte{"test.url": []byte("dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy")},
}
}
+33 -27
View File
@@ -52,32 +52,33 @@ func rollingUpgrade(r ResourceUpdatedHandler, resourceType string, rollingUpgrad
if err != nil {
logrus.Fatalf("Unable to create Kubernetes client error = %v", err)
}
var namespace, name, sshData, envName string
var namespace, name, shaData, envName string
if resourceType == "configmaps" {
namespace = r.Resource.(*v1.ConfigMap).Namespace
name = r.Resource.(*v1.ConfigMap).Name
sshData = helper.ConvertConfigmapToSHA(r.Resource.(*v1.ConfigMap))
shaData = helper.ConvertConfigmapToSHA(r.Resource.(*v1.ConfigMap))
envName = "_CONFIGMAP"
} else if resourceType == "secrets" {
namespace = r.Resource.(*v1.Secret).Namespace
name = r.Resource.(*v1.Secret).Name
sshData = helper.ConvertSecretToSHA(r.Resource.(*v1.Secret))
shaData = helper.ConvertSecretToSHA(r.Resource.(*v1.Secret))
envName = "_SECRET"
}
if rollingUpgradeType == "deployments" {
rollingUpgradeForDeployment(client, namespace, name, sshData, envName)
RollingUpgradeForDeployment(client, namespace, name, shaData, envName)
} else if rollingUpgradeType == "daemonsets" {
rollingUpgradeForDaemonSets(client, namespace, name, sshData, envName)
RollingUpgradeForDaemonSets(client, namespace, name, shaData, envName)
} else if rollingUpgradeType == "statefulSets" {
rollingUpgradeForStatefulSets(client, namespace, name, sshData, envName)
RollingUpgradeForStatefulSets(client, namespace, name, shaData, envName)
}
}
func rollingUpgradeForDeployment(client kubernetes.Interface, namespace string, name string, sshData string, envName string) error {
// RollingUpgradeForDeployment upgrades the deployment if there is any change in configmap or secret data
func RollingUpgradeForDeployment(client kubernetes.Interface, namespace string, name string, shaData string, envName string) error {
deployments, err := client.ExtensionsV1beta1().Deployments(namespace).List(meta_v1.ListOptions{})
if err != nil {
logrus.Fatalf("Failed to list deployments %v", err)
logrus.Errorf("Failed to list deployments %v", err)
}
var updateOnChangeAnnotation string
if envName == "_CONFIGMAP" {
@@ -100,7 +101,7 @@ func rollingUpgradeForDeployment(client kubernetes.Interface, namespace string,
}
}
if matches {
updated := updateContainers(containers, name, sshData, envName)
updated := updateContainers(containers, name, shaData, envName)
if !updated {
logrus.Warnf("Rolling upgrade did not happen")
@@ -108,9 +109,10 @@ func rollingUpgradeForDeployment(client kubernetes.Interface, namespace string,
// update the deployment
_, err := client.ExtensionsV1beta1().Deployments(namespace).Update(&d)
if err != nil {
logrus.Fatalf("Update deployment failed %v", err)
logrus.Errorf("Update deployment failed %v", err)
} else {
logrus.Infof("Updated Deployment %s", d.Name)
}
logrus.Infof("Updated Deployment %s", d.Name)
}
}
}
@@ -118,10 +120,11 @@ func rollingUpgradeForDeployment(client kubernetes.Interface, namespace string,
return nil
}
func rollingUpgradeForDaemonSets(client kubernetes.Interface, namespace string, name string, sshData string, envName string) error {
// RollingUpgradeForDaemonSets upgrades the daemonset if there is any change in configmap or secret data
func RollingUpgradeForDaemonSets(client kubernetes.Interface, namespace string, name string, shaData string, envName string) error {
daemonSets, err := client.ExtensionsV1beta1().DaemonSets(namespace).List(meta_v1.ListOptions{})
if err != nil {
logrus.Fatalf("Failed to list daemonSets %v", err)
logrus.Errorf("Failed to list daemonSets %v", err)
}
var updateOnChangeAnnotation string
@@ -145,7 +148,7 @@ func rollingUpgradeForDaemonSets(client kubernetes.Interface, namespace string,
}
}
if matches {
updated := updateContainers(containers, name, sshData, envName)
updated := updateContainers(containers, name, shaData, envName)
if !updated {
logrus.Warnf("Rolling upgrade did not happen")
@@ -153,9 +156,10 @@ func rollingUpgradeForDaemonSets(client kubernetes.Interface, namespace string,
// update the daemonSet
_, err := client.ExtensionsV1beta1().DaemonSets(namespace).Update(&d)
if err != nil {
logrus.Fatalf("Update daemonSet failed %v", err)
logrus.Errorf("Update daemonSet failed %v", err)
} else {
logrus.Infof("Updated daemonSet %s", d.Name)
}
logrus.Infof("Updated daemonSet %s", d.Name)
}
}
}
@@ -163,10 +167,11 @@ func rollingUpgradeForDaemonSets(client kubernetes.Interface, namespace string,
return nil
}
func rollingUpgradeForStatefulSets(client kubernetes.Interface, namespace string, name string, sshData string, envName string) error {
// RollingUpgradeForStatefulSets upgrades the statefulset if there is any change in configmap or secret data
func RollingUpgradeForStatefulSets(client kubernetes.Interface, namespace string, name string, shaData string, envName string) error {
statefulSets, err := client.AppsV1beta1().StatefulSets(namespace).List(meta_v1.ListOptions{})
if err != nil {
logrus.Fatalf("Failed to list statefulSets %v", err)
logrus.Errorf("Failed to list statefulSets %v", err)
}
var updateOnChangeAnnotation string
if envName == "_CONFIGMAP" {
@@ -189,7 +194,7 @@ func rollingUpgradeForStatefulSets(client kubernetes.Interface, namespace string
}
}
if matches {
updated := updateContainers(containers, name, sshData, envName)
updated := updateContainers(containers, name, shaData, envName)
if !updated {
logrus.Warnf("Rolling upgrade did not happen")
@@ -197,9 +202,10 @@ func rollingUpgradeForStatefulSets(client kubernetes.Interface, namespace string
// update the statefulSet
_, err := client.AppsV1beta1().StatefulSets(namespace).Update(&d)
if err != nil {
logrus.Fatalf("Update statefulSet failed %v", err)
logrus.Errorf("Update statefulSet failed %v", err)
} else {
logrus.Infof("Updated statefulSet %s", d.Name)
}
logrus.Infof("Updated statefulSet %s", d.Name)
}
}
}
@@ -207,7 +213,7 @@ func rollingUpgradeForStatefulSets(client kubernetes.Interface, namespace string
return nil
}
func updateContainers(containers []v1.Container, annotationValue string, sshData string, resourceType string) bool {
func updateContainers(containers []v1.Container, annotationValue string, shaData string, resourceType string) bool {
updated := false
envar := "STAKATER_" + helper.ConvertToEnvVarName(annotationValue) + resourceType
logrus.Infof("Generated environment variable: %s", envar)
@@ -219,9 +225,9 @@ func updateContainers(containers []v1.Container, annotationValue string, sshData
if envs[j].Name == envar {
matched = true
logrus.Infof("%s environment variable found", envar)
if envs[j].Value != sshData {
logrus.Infof("Updating %s to %s", envar, sshData)
envs[j].Value = sshData
if envs[j].Value != shaData {
logrus.Infof("Updating %s to %s", envar, shaData)
envs[j].Value = shaData
updated = true
}
}
@@ -230,11 +236,11 @@ func updateContainers(containers []v1.Container, annotationValue string, sshData
if !matched {
e := v1.EnvVar{
Name: envar,
Value: sshData,
Value: shaData,
}
containers[i].Env = append(containers[i].Env, e)
updated = true
logrus.Infof("%s environment variable does not found, creating a new env with value %s", envar, sshData)
logrus.Infof("%s environment variable does not found, creating a new env with value %s", envar, shaData)
}
}
return updated
@@ -0,0 +1,261 @@
package handlerTester
import (
"os"
"testing"
"time"
"github.com/sirupsen/logrus"
"github.com/stakater/Reloader/internal/pkg/controller"
"github.com/stakater/Reloader/internal/pkg/handler"
helper "github.com/stakater/Reloader/internal/pkg/helper"
"github.com/stakater/Reloader/pkg/kube"
v1_beta1 "k8s.io/api/apps/v1beta1"
"k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
var (
client = getClient()
namespace = "test-handler"
configmapName = "testconfigmap-handler-update-" + helper.RandSeq(5)
secretName = "testsecret-handler-update-" + helper.RandSeq(5)
)
func TestMain(m *testing.M) {
logrus.Infof("Creating namespace %s", namespace)
helper.CreateNamespace(namespace, client)
logrus.Infof("Creating controller")
newController, err := controller.NewController(client, "configMaps", namespace)
if err != nil {
logrus.Errorf("Unable to create NewController error = %v", err)
return
}
stop := make(chan struct{})
defer close(stop)
logrus.Infof("Starting controller")
go newController.Run(1, stop)
time.Sleep(10 * time.Second)
logrus.Infof("Setting up the test resources")
setup()
logrus.Infof("Running Testcases")
retCode := m.Run()
logrus.Infof("tearing down the test resources")
teardown()
os.Exit(retCode)
}
func getClient() *kubernetes.Clientset {
newClient, err := kube.GetClient()
if err != nil {
logrus.Fatalf("Unable to create Kubernetes client error = %v", err)
}
return newClient
}
func setup() {
logrus.Infof("Creating configmap")
configmapClient := client.CoreV1().ConfigMaps(namespace)
_, err := configmapClient.Create(helper.GetConfigmap(namespace, configmapName, "www.google.com"))
if err != nil {
logrus.Errorf("Error in configmap creation: %v", err)
}
time.Sleep(10 * time.Second)
logrus.Infof("Creating secret")
secretClient := client.CoreV1().Secrets(namespace)
data := "dGVzdFNlY3JldEVuY29kaW5nRm9yUmVsb2FkZXI="
_, err = secretClient.Create(helper.GetSecret(namespace, secretName, data))
if err != nil {
logrus.Errorf("Error in secret creation: %v", err)
}
time.Sleep(10 * time.Second)
logrus.Infof("Creating Deployment with configmap")
createDeployment(configmapName, namespace)
logrus.Infof("Creating Deployment with secret")
createDeployment(secretName, namespace)
logrus.Infof("Creating Daemonset with configmap")
createDaemonset(configmapName, namespace)
logrus.Infof("Creating Daemonset with secret")
createDaemonset(secretName, namespace)
logrus.Infof("Creating Statefulset with configmap")
createStatefulset(configmapName, namespace)
logrus.Infof("Creating Statefulset with secret")
createStatefulset(secretName, namespace)
}
func teardown() {
logrus.Infof("Deleting Deployment with configmap")
deploymentError := client.ExtensionsV1beta1().Deployments(namespace).Delete(configmapName, &metav1.DeleteOptions{})
if deploymentError != nil {
logrus.Errorf("Error while deleting deployment with configmap %v", deploymentError)
}
logrus.Infof("Deleting Deployment with secret")
deploymentError = client.ExtensionsV1beta1().Deployments(namespace).Delete(secretName, &metav1.DeleteOptions{})
if deploymentError != nil {
logrus.Errorf("Error while deleting deployment with secret %v", deploymentError)
}
logrus.Infof("Deleting Daemonset with configmap")
daemonsetError := client.ExtensionsV1beta1().DaemonSets(namespace).Delete(configmapName, &metav1.DeleteOptions{})
if daemonsetError != nil {
logrus.Errorf("Error while deleting daemonset with configmap %v", daemonsetError)
}
logrus.Infof("Deleting Deployment with secret")
daemonsetError = client.ExtensionsV1beta1().DaemonSets(namespace).Delete(secretName, &metav1.DeleteOptions{})
if daemonsetError != nil {
logrus.Errorf("Error while deleting daemonset with secret %v", daemonsetError)
}
logrus.Infof("Deleting Statefulset with configmap")
statefulsetError := client.AppsV1beta1().StatefulSets(namespace).Delete(configmapName, &metav1.DeleteOptions{})
if statefulsetError != nil {
logrus.Errorf("Error while deleting statefulset with configmap %v", statefulsetError)
}
logrus.Infof("Deleting Deployment with secret")
statefulsetError = client.AppsV1beta1().StatefulSets(namespace).Delete(secretName, &metav1.DeleteOptions{})
if statefulsetError != nil {
logrus.Errorf("Error while deleting statefulset with secret %v", statefulsetError)
}
logrus.Infof("Deleting Configmap %q.\n", configmapName)
err := client.CoreV1().ConfigMaps(namespace).Delete(configmapName, &metav1.DeleteOptions{})
if err != nil {
logrus.Errorf("Error while deleting the configmap %v", err)
}
time.Sleep(5 * time.Second)
logrus.Infof("Deleting Secret %q.\n", secretName)
err = client.CoreV1().Secrets(namespace).Delete(secretName, &metav1.DeleteOptions{})
if err != nil {
logrus.Errorf("Error while deleting the secret %v", err)
}
time.Sleep(5 * time.Second)
logrus.Infof("Deleting namespace %q.\n", namespace)
helper.DeleteNamespace(namespace, client)
}
func createDeployment(deploymentName string, namespace string) *v1beta1.Deployment {
deploymentClient := client.ExtensionsV1beta1().Deployments(namespace)
deployment := helper.GetDeployment(namespace, deploymentName)
deployment, err := deploymentClient.Create(deployment)
if err != nil {
logrus.Errorf("Error in deployment creation: %v", err)
}
logrus.Infof("Created Deployment %q.\n", deployment.GetObjectMeta().GetName())
return deployment
}
func createDaemonset(daemonsetName string, namespace string) *v1beta1.DaemonSet {
daemonsetClient := client.ExtensionsV1beta1().DaemonSets(namespace)
daemonset := helper.GetDaemonset(namespace, daemonsetName)
daemonset, err := daemonsetClient.Create(daemonset)
if err != nil {
logrus.Errorf("Error in daemonset creation: %v", err)
}
logrus.Infof("Created Deployment %q.\n", daemonset.GetObjectMeta().GetName())
return daemonset
}
func createStatefulset(statefulsetName string, namespace string) *v1_beta1.StatefulSet {
statefulsetClient := client.AppsV1beta1().StatefulSets(namespace)
statefulset := helper.GetStatefulset(namespace, statefulsetName)
statefulset, err := statefulsetClient.Create(statefulset)
if err != nil {
logrus.Errorf("Error in statefulset creation: %v", err)
}
logrus.Infof("Created Statefulset %q.\n", statefulset.GetObjectMeta().GetName())
return statefulset
}
func TestRollingUpgradeForDeploymentWithConfigmap(t *testing.T) {
shaData := helper.ConvertConfigmapToSHA(helper.GetConfigmap(namespace, configmapName, "www.stakater.com"))
handler.RollingUpgradeForDeployment(client, namespace, configmapName, shaData, "_CONFIGMAP")
time.Sleep(5 * time.Second)
logrus.Infof("Verifying deployment update")
updated := helper.VerifyDeploymentUpdate(client, namespace, configmapName, "_CONFIGMAP", shaData)
if !updated {
t.Errorf("Deployment was not updated")
}
}
func TestRollingUpgradeForDeploymentWithSecret(t *testing.T) {
shaData := helper.ConvertSecretToSHA(helper.GetSecret(namespace, secretName, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy"))
handler.RollingUpgradeForDeployment(client, namespace, secretName, shaData, "_SECRET")
time.Sleep(5 * time.Second)
logrus.Infof("Verifying deployment update")
updated := helper.VerifyDeploymentUpdate(client, namespace, secretName, "_SECRET", shaData)
if !updated {
t.Errorf("Deployment was not updated")
}
}
func TestRollingUpgradeForDaemonsetWithConfigmap(t *testing.T) {
shaData := helper.ConvertConfigmapToSHA(helper.GetConfigmap(namespace, configmapName, "www.facebook.com"))
handler.RollingUpgradeForDaemonSets(client, namespace, configmapName, shaData, "_CONFIGMAP")
time.Sleep(5 * time.Second)
logrus.Infof("Verifying daemonset update")
updated := helper.VerifyDaemonsetUpdate(client, namespace, configmapName, "_CONFIGMAP", shaData)
if !updated {
t.Errorf("Daemonset was not updated")
}
}
func TestRollingUpgradeForDaemonsetWithSecret(t *testing.T) {
shaData := helper.ConvertSecretToSHA(helper.GetSecret(namespace, secretName, "d3d3LmZhY2Vib29rLmNvbQ=="))
handler.RollingUpgradeForDaemonSets(client, namespace, secretName, shaData, "_SECRET")
time.Sleep(5 * time.Second)
logrus.Infof("Verifying daemonset update")
updated := helper.VerifyDaemonsetUpdate(client, namespace, secretName, "_SECRET", shaData)
if !updated {
t.Errorf("Daemonset was not updated")
}
}
func TestRollingUpgradeForStatefulsetWithConfigmap(t *testing.T) {
shaData := helper.ConvertConfigmapToSHA(helper.GetConfigmap(namespace, configmapName, "www.twitter.com"))
handler.RollingUpgradeForStatefulSets(client, namespace, configmapName, shaData, "_CONFIGMAP")
time.Sleep(5 * time.Second)
logrus.Infof("Verifying statefulset update")
updated := helper.VerifyStatefulsetUpdate(client, namespace, configmapName, "_CONFIGMAP", shaData)
if !updated {
t.Errorf("Statefulset was not updated")
}
}
func TestRollingUpgradeForStatefulsetWithSecret(t *testing.T) {
shaData := helper.ConvertSecretToSHA(helper.GetSecret(namespace, secretName, "d3d3LnR3aXR0ZXIuY29t"))
handler.RollingUpgradeForStatefulSets(client, namespace, secretName, shaData, "_SECRET")
time.Sleep(5 * time.Second)
logrus.Infof("Verifying statefulset update")
updated := helper.VerifyStatefulsetUpdate(client, namespace, secretName, "_SECRET", shaData)
if !updated {
t.Errorf("Statefulset was not updated")
}
}
+310
View File
@@ -0,0 +1,310 @@
package handler
import (
"math/rand"
"strings"
"time"
"github.com/sirupsen/logrus"
v1_beta1 "k8s.io/api/apps/v1beta1"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
var (
letters = []rune("abcdefghijklmnopqrstuvwxyz")
configmapUpdateOnChangeAnnotation = "reloader.stakater.com/configmap.update-on-change"
secretUpdateOnChangeAnnotation = "reloader.stakater.com/secret.update-on-change"
)
// RandSeq generates a random sequence
func RandSeq(n int) string {
rand.Seed(time.Now().UnixNano())
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
// CreateNamespace creates namespace for testing
func CreateNamespace(namespace string, client kubernetes.Interface) {
_, err := client.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}})
if err != nil {
logrus.Fatalf("Failed to create namespace for testing", err)
} else {
logrus.Infof("Creating namespace for testing = %s", namespace)
}
}
// DeleteNamespace deletes namespace for testing
func DeleteNamespace(namespace string, client kubernetes.Interface) {
err := client.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{})
if err != nil {
logrus.Fatalf("Failed to delete namespace that was created for testing", err)
} else {
logrus.Infof("Deleting namespace for testing = %s", namespace)
}
}
// GetDeployment provides deployment for testing
func GetDeployment(namespace string, deploymentName string) *v1beta1.Deployment {
replicaset := int32(1)
return &v1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: deploymentName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
Annotations: map[string]string{
"reloader.stakater.com/configmap.update-on-change": deploymentName,
"reloader.stakater.com/secret.update-on-change": deploymentName},
},
Spec: v1beta1.DeploymentSpec{
Replicas: &replicaset,
Strategy: v1beta1.DeploymentStrategy{
Type: v1beta1.RollingUpdateDeploymentStrategyType,
},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"secondLabel": "temp"},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Image: "tutum/hello-world",
Name: deploymentName,
Env: []v1.EnvVar{
{
Name: "BUCKET_NAME",
Value: "test",
},
},
},
},
},
},
},
}
}
// GetDaemonset provides daemonset for testing
func GetDaemonset(namespace string, daemonsetName string) *v1beta1.DaemonSet {
return &v1beta1.DaemonSet{
ObjectMeta: metav1.ObjectMeta{
Name: daemonsetName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
Annotations: map[string]string{
"reloader.stakater.com/configmap.update-on-change": daemonsetName,
"reloader.stakater.com/secret.update-on-change": daemonsetName},
},
Spec: v1beta1.DaemonSetSpec{
UpdateStrategy: v1beta1.DaemonSetUpdateStrategy{
Type: v1beta1.RollingUpdateDaemonSetStrategyType,
},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"secondLabel": "temp"},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Image: "tutum/hello-world",
Name: daemonsetName,
Env: []v1.EnvVar{
{
Name: "BUCKET_NAME",
Value: "test",
},
},
},
},
},
},
},
}
}
// GetStatefulset provides statefulset for testing
func GetStatefulset(namespace string, statefulsetName string) *v1_beta1.StatefulSet {
return &v1_beta1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Name: statefulsetName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
Annotations: map[string]string{
"reloader.stakater.com/configmap.update-on-change": statefulsetName,
"reloader.stakater.com/secret.update-on-change": statefulsetName},
},
Spec: v1_beta1.StatefulSetSpec{
UpdateStrategy: v1_beta1.StatefulSetUpdateStrategy{
Type: v1_beta1.RollingUpdateStatefulSetStrategyType,
},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"secondLabel": "temp"},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Image: "tutum/hello-world",
Name: statefulsetName,
Env: []v1.EnvVar{
{
Name: "BUCKET_NAME",
Value: "test",
},
},
},
},
},
},
},
}
}
// GetConfigmap provides configmap for testing
func GetConfigmap(namespace string, configmapName string, testData string) *v1.ConfigMap {
return &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: configmapName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
},
Data: map[string]string{"test.url": testData},
}
}
// GetSecret provides secret for testing
func GetSecret(namespace string, secretName string, data string) *v1.Secret {
return &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Labels: map[string]string{"firstLabel": "temp"},
},
Data: map[string][]byte{"test.url": []byte(data)},
}
}
// VerifyDeploymentUpdate verifies whether deployment has been updated with environment variable or not
func VerifyDeploymentUpdate(client kubernetes.Interface, namespace string, name string, resourceType string, shaData string) bool {
deployments, err := client.ExtensionsV1beta1().Deployments(namespace).List(metav1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list deployments %v", err)
}
for _, d := range deployments.Items {
containers := d.Spec.Template.Spec.Containers
// match deployments with the correct annotation
annotationValue := d.ObjectMeta.Annotations[configmapUpdateOnChangeAnnotation]
if annotationValue != "" {
values := strings.Split(annotationValue, ",")
matches := false
for _, value := range values {
if value == name {
matches = true
break
}
}
if matches {
envName := "STAKATER_" + ConvertToEnvVarName(annotationValue) + resourceType
updated := getResourceSHA(containers, envName)
logrus.Infof("shaData %s", shaData)
logrus.Infof("updated %s", updated)
if updated != shaData {
return false
} else {
return true
}
}
}
}
return false
}
// VerifyDaemonsetUpdate verifies whether daemonset has been updated with environment variable or not
func VerifyDaemonsetUpdate(client kubernetes.Interface, namespace string, name string, resourceType string, shaData string) bool {
daemonsets, err := client.ExtensionsV1beta1().DaemonSets(namespace).List(metav1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list daemonsets %v", err)
}
for _, d := range daemonsets.Items {
containers := d.Spec.Template.Spec.Containers
// match daemonsets with the correct annotation
annotationValue := d.ObjectMeta.Annotations[configmapUpdateOnChangeAnnotation]
if annotationValue != "" {
values := strings.Split(annotationValue, ",")
matches := false
for _, value := range values {
if value == name {
matches = true
break
}
}
if matches {
envName := "STAKATER_" + ConvertToEnvVarName(annotationValue) + resourceType
updated := getResourceSHA(containers, envName)
logrus.Infof("shaData %s", shaData)
logrus.Infof("updated %s", updated)
if updated != shaData {
return false
} else {
return true
}
}
}
}
return false
}
// VerifyStatefulsetUpdate verifies whether statefulset has been updated with environment variable or not
func VerifyStatefulsetUpdate(client kubernetes.Interface, namespace string, name string, resourceType string, shaData string) bool {
statefulsets, err := client.AppsV1beta1().StatefulSets(namespace).List(metav1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list statefulsets %v", err)
}
for _, d := range statefulsets.Items {
containers := d.Spec.Template.Spec.Containers
// match statefulsets with the correct annotation
annotationValue := d.ObjectMeta.Annotations[configmapUpdateOnChangeAnnotation]
if annotationValue != "" {
values := strings.Split(annotationValue, ",")
matches := false
for _, value := range values {
if value == name {
matches = true
break
}
}
if matches {
envName := "STAKATER_" + ConvertToEnvVarName(annotationValue) + resourceType
updated := getResourceSHA(containers, envName)
logrus.Infof("shaData %s", shaData)
logrus.Infof("updated %s", updated)
if updated != shaData {
return false
} else {
return true
}
}
}
}
return false
}
func getResourceSHA(containers []v1.Container, envar string) string {
for i := range containers {
envs := containers[i].Env
for j := range envs {
if envs[j].Name == envar {
return envs[j].Value
}
}
}
return ""
}