package controller import ( "math/rand" "testing" "time" "github.com/sirupsen/logrus" "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") ) 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() if err != nil { logrus.Errorf("Unable to create Kubernetes client error = %v", err) return } namespace := "test-reloader" createNamespace(t, namespace, client) defer deleteNamespace(t, namespace, client) controller, err := NewController(client, "configMaps", namespace) if err != nil { logrus.Errorf("Unable to create NewController error = %v", err) return } stop := make(chan struct{}) defer close(stop) go controller.Run(1, stop) time.Sleep(10 * time.Second) configmapName := configmapNamePrefix + "-update-" + randSeq(5) configmapClient := client.CoreV1().ConfigMaps(namespace) _, err = configmapClient.Create(initConfigmap(namespace, configmapName)) if err != nil { logrus.Fatalf("Fatal error in configmap creation: %v", err) } logrus.Infof("Created Configmap %q.\n", configmapName) time.Sleep(10 * time.Second) deployment := createDeployement(configmapName, namespace, client) logrus.Infof("Updating Configmap %q.\n", configmapName) _, err = configmapClient.Get(configmapName, metav1.GetOptions{}) if err != nil { logrus.Errorf("Error while getting configmap %v", err) } _, updateErr := configmapClient.Update(updateConfigmap(namespace, configmapName)) // TODO: Add functionality to verify reloader functionality here if updateErr != nil { err = controller.client.CoreV1().ConfigMaps(namespace).Delete(configmapName, &metav1.DeleteOptions{}) if err != nil { logrus.Errorf("Error while deleting the configmap %v", err) } logrus.Fatalf("Fatal error in configmap update: %v", updateErr) } time.Sleep(10 * time.Second) 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.Infof("Deleting Configmap %q.\n", configmapName) err = controller.client.CoreV1().ConfigMaps(namespace).Delete(configmapName, &metav1.DeleteOptions{}) if err != nil { logrus.Errorf("Error while deleting the configmap %v", err) } time.Sleep(15 * time.Second) } func createDeployement(deploymentName string, namespace string, client kubernetes.Interface) *v1beta1.Deployment { deploymentClient := client.ExtensionsV1beta1().Deployments(namespace) deployment := initDeployment(namespace, deploymentName) deployment, err := deploymentClient.Create(deployment) if err != nil { logrus.Fatalf("Fatal error in deployment creation: %v", err) } logrus.Infof("Created Deployment %q.\n", deployment.GetObjectMeta().GetName()) return deployment } func TestControllerForUpdatingSecretShouldUpdateDeployment(t *testing.T) { client, err := kube.GetClient() if err != nil { logrus.Errorf("Unable to create Kubernetes client error = %v", err) return } namespace := "test-reloader-secrets" createNamespace(t, namespace, client) defer deleteNamespace(t, namespace, client) controller, err := NewController(client, "secrets", namespace) if err != nil { logrus.Errorf("Unable to create NewController error = %v", err) return } stop := make(chan struct{}) defer close(stop) go controller.Run(1, stop) time.Sleep(10 * time.Second) secretName := secretNamePrefix + "-update-" + randSeq(5) secretClient := client.CoreV1().Secrets(namespace) _, err = secretClient.Create(initSecret(namespace, secretName)) if err != nil { logrus.Fatalf("Fatal error in secret creation: %v", err) } logrus.Infof("Created Secret %q.\n", secretName) time.Sleep(10 * time.Second) logrus.Infof("Updating Secret %q.\n", secretName) _, err = secretClient.Get(secretName, metav1.GetOptions{}) if err != nil { logrus.Errorf("Error while getting secret %v", err) } _, updateErr := secretClient.Update(updateSecret(namespace, secretName)) // TODO: Add functionality to verify reloader functionality here if updateErr != nil { err := controller.client.CoreV1().Secrets(namespace).Delete(secretName, &metav1.DeleteOptions{}) if err != nil { logrus.Errorf("Error while deleting the secret %v", err) } logrus.Errorf("Error while updating the secret %v", err) } time.Sleep(10 * time.Second) logrus.Infof("Deleting Secret %q.\n", secretName) err = controller.client.CoreV1().Secrets(namespace).Delete(secretName, &metav1.DeleteOptions{}) if err != nil { logrus.Errorf("Error while deleting the secret %v", err) } 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/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) { 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) *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.stakater.com"}, } } 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")}, } }