Implement PR-2 review comments

This commit is contained in:
faizanahmad055
2018-07-24 21:05:50 +05:00
parent 5b467b731c
commit 2cac0cc713
12 changed files with 529 additions and 435 deletions
+108
View File
@@ -0,0 +1,108 @@
package callbacks
import (
"github.com/sirupsen/logrus"
"github.com/stakater/Reloader/internal/pkg/util"
apps_v1beta1 "k8s.io/api/apps/v1beta1"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
//ItemsFunc is a generic function to return a specific resource array in given namespace
type ItemsFunc func(kubernetes.Interface, string) []interface{}
//ContainersFunc is a generic func to return containers
type ContainersFunc func(interface{}) []v1.Container
//UpdateFunc performs the resource update
type UpdateFunc func(kubernetes.Interface, string, interface{}) error
type ResourceTypeFunc func() string
//RollingUpgradeFuncs contains generic functions to perform rolling upgrade
type RollingUpgradeFuncs struct {
ItemsFunc ItemsFunc
ContainersFunc ContainersFunc
UpdateFunc UpdateFunc
ResourceTypeFunc ResourceTypeFunc
}
// GetDeploymentItems returns the deployments in given namespace
func GetDeploymentItems(client kubernetes.Interface, namespace string) []interface{} {
deployments, err := client.ExtensionsV1beta1().Deployments(namespace).List(meta_v1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list deployments %v", err)
}
return util.InterfaceSlice(deployments.Items)
}
// GetDaemonSetItems returns the daemonSet in given namespace
func GetDaemonSetItems(client kubernetes.Interface, namespace string) []interface{} {
daemonSets, err := client.ExtensionsV1beta1().DaemonSets(namespace).List(meta_v1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list daemonSets %v", err)
}
return util.InterfaceSlice(daemonSets.Items)
}
// GetStatefulSetItems returns the statefulSet in given namespace
func GetStatefulSetItems(client kubernetes.Interface, namespace string) []interface{} {
statefulSets, err := client.AppsV1beta1().StatefulSets(namespace).List(meta_v1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list statefulSets %v", err)
}
return util.InterfaceSlice(statefulSets.Items)
}
// GetDeploymentContainers returns the containers of given deployment
func GetDeploymentContainers(item interface{}) []v1.Container {
return item.(v1beta1.Deployment).Spec.Template.Spec.Containers
}
// GetDaemonSetContainers returns the containers of given daemonset
func GetDaemonSetContainers(item interface{}) []v1.Container {
return item.(v1beta1.DaemonSet).Spec.Template.Spec.Containers
}
// GetStatefulsetContainers returns the containers of given statefulSet
func GetStatefulsetContainers(item interface{}) []v1.Container {
return item.(apps_v1beta1.StatefulSet).Spec.Template.Spec.Containers
}
// GetDeploymentTypeName returns Deployment resource type
func GetDeploymentTypeName() string {
return "Deployment"
}
// GetDaemonSetTypeName returns DaemonSet resource type
func GetDaemonSetTypeName() string {
return "DaemonSet"
}
// GetStatefulSetTypeName returns StatefulSet resource type
func GetStatefulSetTypeName() string {
return "StatefulSet"
}
// UpdateDeployment performs rolling upgrade on deployment
func UpdateDeployment(client kubernetes.Interface, namespace string, resource interface{}) error {
deployment := resource.(v1beta1.Deployment)
_, err := client.ExtensionsV1beta1().Deployments(namespace).Update(&deployment)
return err
}
// UpdateDaemonSet performs rolling upgrade on daemonSet
func UpdateDaemonSet(client kubernetes.Interface, namespace string, resource interface{}) error {
daemonSet := resource.(v1beta1.DaemonSet)
_, err := client.ExtensionsV1beta1().DaemonSets(namespace).Update(&daemonSet)
return err
}
// UpdateStatefulset performs rolling upgrade on statefulSet
func UpdateStatefulset(client kubernetes.Interface, namespace string, resource interface{}) error {
statefulSet := resource.(apps_v1beta1.StatefulSet)
_, err := client.AppsV1beta1().StatefulSets(namespace).Update(&statefulSet)
return err
}
+1 -1
View File
@@ -5,4 +5,4 @@ const (
ConfigmapUpdateOnChangeAnnotation = "configmap.reloader.stakater.com/reload"
// SecretUpdateOnChangeAnnotation is an annotation to detect changes in secrets
SecretUpdateOnChangeAnnotation = "secret.reloader.stakater.com/reload"
)
)
+5 -5
View File
@@ -1,10 +1,10 @@
package constants
const (
// ConfigmapEnvarPostfix is a postfix for configmap envVar
ConfigmapEnvarPostfix = "_CONFIGMAP"
// SecretEnvarPostfix is a postfix for secret envVar
SecretEnvarPostfix = "_SECRET"
// ConfigmapEnvVarPostfix is a postfix for configmap envVar
ConfigmapEnvVarPostfix = "_CONFIGMAP"
// SecretEnvVarPostfix is a postfix for secret envVar
SecretEnvVarPostfix = "_SECRET"
// EnvVarPrefix is a Prefix for environment variable
EnvVarPrefix = "STAKATER_"
)
)
-1
View File
@@ -64,7 +64,6 @@ func (c *Controller) Update(old interface{}, new interface{}) {
// Delete function to add an object to the queue in case of deleting a resource
func (c *Controller) Delete(old interface{}) {
// TODO Added this function for future usecase
logrus.Infof("Resource deletion has been detected but no further implementation found to take action")
}
+216 -85
View File
@@ -6,15 +6,15 @@ import (
"time"
"github.com/sirupsen/logrus"
"github.com/stakater/Reloader/internal/pkg/common"
"github.com/stakater/Reloader/internal/pkg/callbacks"
"github.com/stakater/Reloader/internal/pkg/constants"
"github.com/stakater/Reloader/internal/pkg/testutil"
"github.com/stakater/Reloader/internal/pkg/util"
"github.com/stakater/Reloader/pkg/kube"
"k8s.io/client-go/kubernetes"
)
var (
client = getClient()
client = testutil.GetClient()
namespace = "test-reloader"
configmapNamePrefix = "testconfigmap-reloader"
secretNamePrefix = "testsecret-reloader"
@@ -51,19 +51,11 @@ func TestMain(m *testing.M) {
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
}
// Perform rolling upgrade on deployment and create env var upon updating the configmap
func TestControllerUpdatingConfigmapShouldCreateEnvInDeployment(t *testing.T) {
// Creating configmap
configmapName := configmapNamePrefix + "-update-" + common.RandSeq(5)
configmapName := configmapNamePrefix + "-update-" + testutil.RandSeq(5)
configmapClient, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
if err != nil {
t.Errorf("Error while creating the configmap %v", err)
@@ -84,7 +76,19 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDeployment(t *testing.T) {
// Verifying deployment update
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.stakater.com")
updated := testutil.VerifyDeploymentUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceTypeFunc: callbacks.GetDeploymentTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
if !updated {
t.Errorf("Deployment was not updated")
}
@@ -107,7 +111,7 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDeployment(t *testing.T) {
// Perform rolling upgrade on deployment and update env var upon updating the configmap
func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
// Creating secret
configmapName := configmapNamePrefix + "-update-" + common.RandSeq(5)
configmapName := configmapNamePrefix + "-update-" + testutil.RandSeq(5)
configmapClient, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
if err != nil {
t.Errorf("Error while creating the configmap %v", err)
@@ -134,7 +138,21 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
// Verifying deployment update
logrus.Infof("Verifying env var has been updated")
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "aurorasolutions.io")
updated := testutil.VerifyDeploymentUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceTypeFunc: callbacks.GetDeploymentTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
if !updated {
t.Errorf("Deployment was not updated")
}
@@ -157,7 +175,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
// Do not Perform rolling upgrade on deployment and create env var upon updating the labels configmap
func TestControllerUpdatingConfigmapLabelsShouldNotCreateorUpdateEnvInDeployment(t *testing.T) {
// Creating configmap
configmapName := configmapNamePrefix + "-update-" + common.RandSeq(5)
configmapName := configmapNamePrefix + "-update-" + testutil.RandSeq(5)
configmapClient, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
if err != nil {
t.Errorf("Error while creating the configmap %v", err)
@@ -178,7 +196,19 @@ func TestControllerUpdatingConfigmapLabelsShouldNotCreateorUpdateEnvInDeployment
// Verifying deployment update
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.google.com")
updated := testutil.VerifyDeploymentUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceTypeFunc: callbacks.GetDeploymentTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
if updated {
t.Errorf("Deployment should not be updated by changing label")
}
@@ -201,7 +231,7 @@ func TestControllerUpdatingConfigmapLabelsShouldNotCreateorUpdateEnvInDeployment
// Perform rolling upgrade on secret and create a env var upon updating the secret
func TestControllerUpdatingSecretShouldCreateEnvInDeployment(t *testing.T) {
// Creating secret
secretName := secretNamePrefix + "-update-" + common.RandSeq(5)
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
secretClient, err := testutil.CreateSecret(client, namespace, secretName, data)
if err != nil {
t.Errorf("Error in secret creation: %v", err)
@@ -222,7 +252,19 @@ func TestControllerUpdatingSecretShouldCreateEnvInDeployment(t *testing.T) {
// Verifying Upgrade
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, newData)
updated := testutil.VerifyDeploymentUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceTypeFunc: callbacks.GetDeploymentTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
if !updated {
t.Errorf("Deployment was not updated")
}
@@ -245,7 +287,7 @@ func TestControllerUpdatingSecretShouldCreateEnvInDeployment(t *testing.T) {
// Perform rolling upgrade on deployment and update env var upon updating the secret
func TestControllerUpdatingSecretShouldUpdateEnvInDeployment(t *testing.T) {
// Creating secret
secretName := secretNamePrefix + "-update-" + common.RandSeq(5)
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
secretClient, err := testutil.CreateSecret(client, namespace, secretName, data)
if err != nil {
t.Errorf("Error in secret creation: %v", err)
@@ -272,7 +314,19 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDeployment(t *testing.T) {
// Verifying Upgrade
logrus.Infof("Verifying env var has been updated")
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, updatedData)
updated := testutil.VerifyDeploymentUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceTypeFunc: callbacks.GetDeploymentTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
if !updated {
t.Errorf("Deployment was not updated")
}
@@ -295,7 +349,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDeployment(t *testing.T) {
// Do not Perform rolling upgrade on secret and create or update a env var upon updating the label in secret
func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDeployment(t *testing.T) {
// Creating secret
secretName := secretNamePrefix + "-update-" + common.RandSeq(5)
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
secretClient, err := testutil.CreateSecret(client, namespace, secretName, data)
if err != nil {
t.Errorf("Error in secret creation: %v", err)
@@ -315,7 +369,19 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDeployment(t
// Verifying Upgrade
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, data)
updated := testutil.VerifyDeploymentUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceTypeFunc: callbacks.GetDeploymentTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
if updated {
t.Errorf("Deployment should not be updated by changing label in secret")
}
@@ -338,7 +404,7 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDeployment(t
// Perform rolling upgrade on DaemonSet and create env var upon updating the configmap
func TestControllerUpdatingConfigmapShouldCreateEnvInDaemonSet(t *testing.T) {
// Creating configmap
configmapName := configmapNamePrefix + "-update-" + common.RandSeq(5)
configmapName := configmapNamePrefix + "-update-" + testutil.RandSeq(5)
configmapClient, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
if err != nil {
t.Errorf("Error while creating the configmap %v", err)
@@ -359,7 +425,19 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDaemonSet(t *testing.T) {
// Verifying DaemonSet update
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.stakater.com")
updated := testutil.VerifyDaemonSetUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceTypeFunc: callbacks.GetDaemonSetTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
}
@@ -382,7 +460,7 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDaemonSet(t *testing.T) {
// Perform rolling upgrade on DaemonSet and update env var upon updating the configmap
func TestControllerForUpdatingConfigmapShouldUpdateDaemonSet(t *testing.T) {
// Creating secret
configmapName := configmapNamePrefix + "-update-" + common.RandSeq(5)
configmapName := configmapNamePrefix + "-update-" + testutil.RandSeq(5)
configmapClient, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
if err != nil {
t.Errorf("Error while creating the configmap %v", err)
@@ -409,7 +487,19 @@ func TestControllerForUpdatingConfigmapShouldUpdateDaemonSet(t *testing.T) {
// Verifying DaemonSet update
logrus.Infof("Verifying env var has been updated")
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "aurorasolutions.io")
updated := testutil.VerifyDaemonSetUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceTypeFunc: callbacks.GetDaemonSetTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
}
@@ -432,7 +522,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateDaemonSet(t *testing.T) {
// Perform rolling upgrade on secret and create a env var upon updating the secret
func TestControllerUpdatingSecretShouldCreateEnvInDaemonSet(t *testing.T) {
// Creating secret
secretName := secretNamePrefix + "-update-" + common.RandSeq(5)
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
secretClient, err := testutil.CreateSecret(client, namespace, secretName, data)
if err != nil {
t.Errorf("Error in secret creation: %v", err)
@@ -453,7 +543,19 @@ func TestControllerUpdatingSecretShouldCreateEnvInDaemonSet(t *testing.T) {
// Verifying Upgrade
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, newData)
updated := testutil.VerifyDaemonSetUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceTypeFunc: callbacks.GetDaemonSetTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
}
@@ -476,7 +578,7 @@ func TestControllerUpdatingSecretShouldCreateEnvInDaemonSet(t *testing.T) {
// Perform rolling upgrade on DaemonSet and update env var upon updating the secret
func TestControllerUpdatingSecretShouldUpdateEnvInDaemonSet(t *testing.T) {
// Creating secret
secretName := secretNamePrefix + "-update-" + common.RandSeq(5)
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
secretClient, err := testutil.CreateSecret(client, namespace, secretName, data)
if err != nil {
t.Errorf("Error in secret creation: %v", err)
@@ -493,6 +595,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDaemonSet(t *testing.T) {
if err != nil {
t.Errorf("Error while updating secret %v", err)
}
time.Sleep(5 * time.Second)
// Updating Secret
err = testutil.UpdateSecret(secretClient, namespace, secretName, "", updatedData)
@@ -503,7 +606,19 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDaemonSet(t *testing.T) {
// Verifying Upgrade
logrus.Infof("Verifying env var has been updated")
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, updatedData)
updated := testutil.VerifyDaemonSetUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceTypeFunc: callbacks.GetDaemonSetTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
}
@@ -526,7 +641,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDaemonSet(t *testing.T) {
// Do not Perform rolling upgrade on secret and create or update a env var upon updating the label in secret
func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDaemonSet(t *testing.T) {
// Creating secret
secretName := secretNamePrefix + "-update-" + common.RandSeq(5)
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
secretClient, err := testutil.CreateSecret(client, namespace, secretName, data)
if err != nil {
t.Errorf("Error in secret creation: %v", err)
@@ -546,7 +661,19 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDaemonSet(t *
// Verifying Upgrade
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, data)
updated := testutil.VerifyDaemonSetUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceTypeFunc: callbacks.GetDaemonSetTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
if updated {
t.Errorf("DaemonSet should not be updated by changing label in secret")
}
@@ -569,7 +696,7 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDaemonSet(t *
// Perform rolling upgrade on StatefulSet and create env var upon updating the configmap
func TestControllerUpdatingConfigmapShouldCreateEnvInStatefulSet(t *testing.T) {
// Creating configmap
configmapName := configmapNamePrefix + "-update-" + common.RandSeq(5)
configmapName := configmapNamePrefix + "-update-" + testutil.RandSeq(5)
configmapClient, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
if err != nil {
t.Errorf("Error while creating the configmap %v", err)
@@ -590,7 +717,19 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInStatefulSet(t *testing.T) {
// Verifying StatefulSet update
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.stakater.com")
updated := testutil.VerifyStatefulSetUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceTypeFunc: callbacks.GetStatefulSetTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")
}
@@ -613,7 +752,7 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInStatefulSet(t *testing.T) {
// Perform rolling upgrade on StatefulSet and update env var upon updating the configmap
func TestControllerForUpdatingConfigmapShouldUpdateStatefulSet(t *testing.T) {
// Creating secret
configmapName := configmapNamePrefix + "-update-" + common.RandSeq(5)
configmapName := configmapNamePrefix + "-update-" + testutil.RandSeq(5)
configmapClient, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
if err != nil {
t.Errorf("Error while creating the configmap %v", err)
@@ -640,7 +779,19 @@ func TestControllerForUpdatingConfigmapShouldUpdateStatefulSet(t *testing.T) {
// Verifying StatefulSet update
logrus.Infof("Verifying env var has been updated")
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "aurorasolutions.io")
updated := testutil.VerifyStatefulSetUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceTypeFunc: callbacks.GetStatefulSetTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")
}
@@ -660,54 +811,10 @@ func TestControllerForUpdatingConfigmapShouldUpdateStatefulSet(t *testing.T) {
time.Sleep(5 * time.Second)
}
// Do not Perform rolling upgrade on StatefulSet and create env var upon updating the labels configmap
func TestControllerUpdatingConfigmapLabelsShouldNotCreateorUpdateEnvInStatefulSet(t *testing.T) {
// Creating configmap
configmapName := configmapNamePrefix + "-update-" + common.RandSeq(5)
configmapClient, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
if err != nil {
t.Errorf("Error while creating the configmap %v", err)
}
// Creating StatefulSet
_, err = testutil.CreateStatefulSet(client, configmapName, namespace)
if err != nil {
t.Errorf("Error in StatefulSet creation: %v", err)
}
// Updating configmap for first time
updateErr := testutil.UpdateConfigMap(configmapClient, namespace, configmapName, "test", "www.google.com")
if updateErr != nil {
t.Errorf("Configmap was not updated")
}
// Verifying StatefulSet update
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.google.com")
updated := testutil.VerifyStatefulSetUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
if updated {
t.Errorf("StatefulSet should not be updated by changing label")
}
time.Sleep(5 * time.Second)
// Deleting StatefulSet
err = testutil.DeleteStatefulSet(client, namespace, configmapName)
if err != nil {
logrus.Errorf("Error while deleting the StatefulSet %v", err)
}
// Deleting configmap
err = testutil.DeleteConfigMap(client, namespace, configmapName)
if err != nil {
logrus.Errorf("Error while deleting the configmap %v", err)
}
time.Sleep(5 * time.Second)
}
// Perform rolling upgrade on secret and create a env var upon updating the secret
func TestControllerUpdatingSecretShouldCreateEnvInStatefulSet(t *testing.T) {
// Creating secret
secretName := secretNamePrefix + "-update-" + common.RandSeq(5)
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
secretClient, err := testutil.CreateSecret(client, namespace, secretName, data)
if err != nil {
t.Errorf("Error in secret creation: %v", err)
@@ -728,7 +835,19 @@ func TestControllerUpdatingSecretShouldCreateEnvInStatefulSet(t *testing.T) {
// Verifying Upgrade
logrus.Infof("Verifying env var has been created")
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, newData)
updated := testutil.VerifyStatefulSetUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceTypeFunc: callbacks.GetStatefulSetTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")
}
@@ -751,7 +870,7 @@ func TestControllerUpdatingSecretShouldCreateEnvInStatefulSet(t *testing.T) {
// Perform rolling upgrade on StatefulSet and update env var upon updating the secret
func TestControllerUpdatingSecretShouldUpdateEnvInStatefulSet(t *testing.T) {
// Creating secret
secretName := secretNamePrefix + "-update-" + common.RandSeq(5)
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
secretClient, err := testutil.CreateSecret(client, namespace, secretName, data)
if err != nil {
t.Errorf("Error in secret creation: %v", err)
@@ -778,7 +897,19 @@ func TestControllerUpdatingSecretShouldUpdateEnvInStatefulSet(t *testing.T) {
// Verifying Upgrade
logrus.Infof("Verifying env var has been updated")
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, updatedData)
updated := testutil.VerifyStatefulSetUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceTypeFunc: callbacks.GetStatefulSetTypeName,
}
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")
}
+3 -3
View File
@@ -7,9 +7,9 @@ import (
// TestGenerateSHA generates the sha from given data and verifies whether it is correct or not
func TestGenerateSHA(t *testing.T) {
data := "www.stakater.com"
sha := GenerateSHA(data)
length := len(sha)
if length != 40 {
sha := "abd4ed82fb04548388a6cf3c339fd9dc84d275df"
result := GenerateSHA(data)
if result != sha {
t.Errorf("Failed to generate SHA")
}
}
+55 -137
View File
@@ -5,15 +5,12 @@ import (
"strings"
"github.com/sirupsen/logrus"
"github.com/stakater/Reloader/internal/pkg/common"
"github.com/stakater/Reloader/internal/pkg/callbacks"
"github.com/stakater/Reloader/internal/pkg/constants"
"github.com/stakater/Reloader/internal/pkg/crypto"
"github.com/stakater/Reloader/internal/pkg/util"
"github.com/stakater/Reloader/pkg/kube"
apps_v1beta1 "k8s.io/api/apps/v1beta1"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
@@ -23,30 +20,6 @@ type ResourceUpdatedHandler struct {
OldResource interface{}
}
//Config contains rolling upgrade configuration parameters
type Config struct {
namespace string
resourceName string
annotation string
shaValue string
}
//ItemsFunc is a generic function to return a specific resource array in given namespace
type ItemsFunc func(kubernetes.Interface, string) []interface{}
//ContainersFunc is a generic func to return containers
type ContainersFunc func(interface{}) []v1.Container
//UpdateFunc performs the resource update
type UpdateFunc func(kubernetes.Interface, string, interface{}) error
//RollingUpgradeFuncs contains generic functions to perform rolling upgrade
type RollingUpgradeFuncs struct {
ItemsFunc ItemsFunc
ContainersFunc ContainersFunc
UpdateFunc UpdateFunc
}
// Handle processes the updated resource
func (r ResourceUpdatedHandler) Handle() error {
if r.Resource == nil || r.OldResource == nil {
@@ -54,89 +27,29 @@ func (r ResourceUpdatedHandler) Handle() error {
} else {
logrus.Infof("Detected changes in object %s", r.Resource)
// process resource based on its type
rollingUpgrade(r, RollingUpgradeFuncs{
ItemsFunc: GetDeploymentItems,
ContainersFunc: GetDeploymentContainers,
UpdateFunc: UpdateDeployment,
rollingUpgrade(r, callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceTypeFunc: callbacks.GetDeploymentTypeName,
})
rollingUpgrade(r, RollingUpgradeFuncs{
ItemsFunc: GetDaemonSetItems,
ContainersFunc: GetDaemonSetContainers,
UpdateFunc: UpdateDaemonSet,
rollingUpgrade(r, callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceTypeFunc: callbacks.GetDaemonSetTypeName,
})
rollingUpgrade(r, RollingUpgradeFuncs{
ItemsFunc: GetStatefulSetItems,
ContainersFunc: GetStatefulsetContainers,
UpdateFunc: UpdateStatefulset,
rollingUpgrade(r, callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceTypeFunc: callbacks.GetStatefulSetTypeName,
})
}
return nil
}
// GetDeploymentItems returns the deployments in given namespace
func GetDeploymentItems(client kubernetes.Interface, namespace string) []interface{} {
deployments, err := client.ExtensionsV1beta1().Deployments(namespace).List(meta_v1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list deployments %v", err)
}
return util.InterfaceSlice(deployments.Items)
}
// GetDaemonSetItems returns the daemonSet in given namespace
func GetDaemonSetItems(client kubernetes.Interface, namespace string) []interface{} {
daemonSets, err := client.ExtensionsV1beta1().DaemonSets(namespace).List(meta_v1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list daemonSets %v", err)
}
return util.InterfaceSlice(daemonSets.Items)
}
// GetStatefulSetItems returns the statefulSet in given namespace
func GetStatefulSetItems(client kubernetes.Interface, namespace string) []interface{} {
statefulSets, err := client.AppsV1beta1().StatefulSets(namespace).List(meta_v1.ListOptions{})
if err != nil {
logrus.Errorf("Failed to list statefulSets %v", err)
}
return util.InterfaceSlice(statefulSets.Items)
}
// GetDeploymentContainers returns the containers of given deployment
func GetDeploymentContainers(item interface{}) []v1.Container {
return item.(v1beta1.Deployment).Spec.Template.Spec.Containers
}
// GetDaemonSetContainers returns the containers of given daemonset
func GetDaemonSetContainers(item interface{}) []v1.Container {
return item.(v1beta1.DaemonSet).Spec.Template.Spec.Containers
}
// GetStatefulsetContainers returns the containers of given statefulSet
func GetStatefulsetContainers(item interface{}) []v1.Container {
return item.(apps_v1beta1.StatefulSet).Spec.Template.Spec.Containers
}
// UpdateDeployment performs rolling upgrade on deployment
func UpdateDeployment(client kubernetes.Interface, namespace string, resource interface{}) error {
deployment := resource.(v1beta1.Deployment)
_, err := client.ExtensionsV1beta1().Deployments(namespace).Update(&deployment)
return err
}
// UpdateDaemonSet performs rolling upgrade on daemonSet
func UpdateDaemonSet(client kubernetes.Interface, namespace string, resource interface{}) error {
daemonSet := resource.(v1beta1.DaemonSet)
_, err := client.ExtensionsV1beta1().DaemonSets(namespace).Update(&daemonSet)
return err
}
// UpdateStatefulset performs rolling upgrade on statefulSet
func UpdateStatefulset(client kubernetes.Interface, namespace string, resource interface{}) error {
statefulSet := resource.(apps_v1beta1.StatefulSet)
_, err := client.AppsV1beta1().StatefulSets(namespace).Update(&statefulSet)
return err
}
func rollingUpgrade(r ResourceUpdatedHandler, upgradeFuncs RollingUpgradeFuncs) {
func rollingUpgrade(r ResourceUpdatedHandler, upgradeFuncs callbacks.RollingUpgradeFuncs) {
client, err := kube.GetClient()
if err != nil {
logrus.Fatalf("Unable to create Kubernetes client error = %v", err)
@@ -144,7 +57,7 @@ func rollingUpgrade(r ResourceUpdatedHandler, upgradeFuncs RollingUpgradeFuncs)
config, envVarPostfix, oldSHAData := getConfig(r)
if config.shaValue != oldSHAData {
if config.SHAValue != oldSHAData {
err = PerformRollingUpgrade(client, config, envVarPostfix, upgradeFuncs)
if err != nil {
logrus.Fatalf("Rolling upgrade failed with error = %v", err)
@@ -154,60 +67,66 @@ func rollingUpgrade(r ResourceUpdatedHandler, upgradeFuncs RollingUpgradeFuncs)
}
}
func getConfig(r ResourceUpdatedHandler) (Config, string, string) {
var shaData, oldSHAData, envVarPostfix string
var config Config
func getConfig(r ResourceUpdatedHandler) (util.Config, string, string) {
var oldSHAData, envVarPostfix string
var config util.Config
if _, ok := r.Resource.(*v1.ConfigMap); ok {
logrus.Infof("Performing 'Updated' action for resource of type 'configmap'")
configmap := r.Resource.(*v1.ConfigMap)
shaData = getSHAfromConfigmap(configmap.Data)
oldSHAData = getSHAfromConfigmap(r.OldResource.(*v1.ConfigMap).Data)
config = Config{
namespace: configmap.Namespace,
resourceName: configmap.Name,
annotation: constants.ConfigmapUpdateOnChangeAnnotation,
shaValue: shaData,
}
envVarPostfix = constants.ConfigmapEnvarPostfix
config = getConfigmapConfig(r)
envVarPostfix = constants.ConfigmapEnvVarPostfix
} else if _, ok := r.Resource.(*v1.Secret); ok {
logrus.Infof("Performing 'Updated' action for resource of type 'secret'")
secret := r.Resource.(*v1.Secret)
shaData = getSHAfromSecret(secret.Data)
oldSHAData = getSHAfromSecret(r.OldResource.(*v1.Secret).Data)
config = Config{
namespace: secret.Namespace,
resourceName: secret.Name,
annotation: constants.SecretUpdateOnChangeAnnotation,
shaValue: shaData,
}
envVarPostfix = constants.SecretEnvarPostfix
config = getSecretConfig(r)
envVarPostfix = constants.SecretEnvVarPostfix
} else {
logrus.Warnf("Invalid resource: Resource should be 'Secret' or 'Configmap' but found, %v", r.Resource)
}
return config, envVarPostfix, oldSHAData
}
func getConfigmapConfig(r ResourceUpdatedHandler) util.Config {
configmap := r.Resource.(*v1.ConfigMap)
return util.Config{
Namespace: configmap.Namespace,
ResourceName: configmap.Name,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
SHAValue: getSHAfromConfigmap(configmap.Data),
}
}
func getSecretConfig(r ResourceUpdatedHandler) util.Config {
secret := r.Resource.(*v1.Secret)
return util.Config{
Namespace: secret.Namespace,
ResourceName: secret.Name,
Annotation: constants.SecretUpdateOnChangeAnnotation,
SHAValue: getSHAfromSecret(secret.Data),
}
}
// PerformRollingUpgrade upgrades the deployment if there is any change in configmap or secret data
func PerformRollingUpgrade(client kubernetes.Interface, config Config, envarPostfix string, upgradeFuncs RollingUpgradeFuncs) error {
items := upgradeFuncs.ItemsFunc(client, config.namespace)
func PerformRollingUpgrade(client kubernetes.Interface, config util.Config, envarPostfix string, upgradeFuncs callbacks.RollingUpgradeFuncs) error {
items := upgradeFuncs.ItemsFunc(client, config.Namespace)
var err error
for _, i := range items {
containers := upgradeFuncs.ContainersFunc(i)
// find correct annotation and update the resource
annotationValue := util.ToObjectMeta(i).Annotations[config.annotation]
annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation]
if annotationValue != "" {
values := strings.Split(annotationValue, ",")
for _, value := range values {
if value == config.resourceName {
updated := updateContainers(containers, value, config.shaValue, envarPostfix)
if value == config.ResourceName {
updated := updateContainers(containers, value, config.SHAValue, envarPostfix)
if !updated {
logrus.Warnf("Rolling upgrade did not happen")
} else {
err = upgradeFuncs.UpdateFunc(client, config.namespace, i)
err = upgradeFuncs.UpdateFunc(client, config.Namespace, i)
if err != nil {
logrus.Errorf("Update deployment failed %v", err)
logrus.Errorf("Update %s failed %v", upgradeFuncs.ResourceTypeFunc, err)
} else {
logrus.Infof("Updated Deployment %s", config.resourceName)
logrus.Infof("Updated %s of type %s", config.ResourceName, upgradeFuncs.ResourceTypeFunc)
}
break
}
@@ -220,7 +139,7 @@ func PerformRollingUpgrade(client kubernetes.Interface, config Config, envarPost
func updateContainers(containers []v1.Container, annotationValue string, shaData string, envarPostfix string) bool {
updated := false
envar := constants.EnvVarPrefix + common.ConvertToEnvVarName(annotationValue) + envarPostfix
envar := constants.EnvVarPrefix + util.ConvertToEnvVarName(annotationValue) + envarPostfix
logrus.Infof("Generated environment variable: %s", envar)
for i := range containers {
envs := containers[i].Env
@@ -247,7 +166,7 @@ func updateEnvVar(envs []v1.EnvVar, envar string, shaData string) bool {
if envs[j].Name == envar {
logrus.Infof("%s environment variable found", envar)
if envs[j].Value != shaData {
logrus.Infof("Updating %s to %s", envar, shaData)
logrus.Infof("Updating %s", envar)
envs[j].Value = shaData
return true
}
@@ -267,7 +186,6 @@ func getSHAfromConfigmap(data map[string]string) string {
func getSHAfromSecret(data map[string][]byte) string {
values := []string{}
logrus.Infof("Generating SHA for secret data")
for k, v := range data {
values = append(values, k+"="+string(v[:]))
}
+77 -80
View File
@@ -6,18 +6,17 @@ import (
"time"
"github.com/sirupsen/logrus"
"github.com/stakater/Reloader/internal/pkg/common"
"github.com/stakater/Reloader/internal/pkg/callbacks"
"github.com/stakater/Reloader/internal/pkg/constants"
"github.com/stakater/Reloader/internal/pkg/testutil"
"github.com/stakater/Reloader/pkg/kube"
"k8s.io/client-go/kubernetes"
"github.com/stakater/Reloader/internal/pkg/util"
)
var (
client = getClient()
client = testutil.GetClient()
namespace = "test-handler"
configmapName = "testconfigmap-handler-update-" + common.RandSeq(5)
secretName = "testsecret-handler-update-" + common.RandSeq(5)
configmapName = "testconfigmap-handler-" + testutil.RandSeq(5)
secretName = "testsecret-handler-" + testutil.RandSeq(5)
)
func TestMain(m *testing.M) {
@@ -37,14 +36,6 @@ func TestMain(m *testing.M) {
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() {
// Creating configmap
_, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
@@ -153,26 +144,27 @@ func teardown() {
func TestRollingUpgradeForDeploymentWithConfigmap(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, configmapName, "www.stakater.com")
config := Config{
namespace: namespace,
resourceName: configmapName,
shaValue: shaData,
annotation: constants.ConfigmapUpdateOnChangeAnnotation,
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
deploymentFuncs := RollingUpgradeFuncs{
ItemsFunc: GetDeploymentItems,
ContainersFunc: GetDeploymentContainers,
UpdateFunc: UpdateDeployment,
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceTypeFunc: callbacks.GetDeploymentTypeName,
}
err := PerformRollingUpgrade(client, config, constants.ConfigmapEnvarPostfix, deploymentFuncs)
err := PerformRollingUpgrade(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
time.Sleep(5 * time.Second)
if err != nil {
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
}
logrus.Infof("Verifying deployment update")
updated := testutil.VerifyDeploymentUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
if !updated {
t.Errorf("Deployment was not updated")
}
@@ -180,26 +172,27 @@ func TestRollingUpgradeForDeploymentWithConfigmap(t *testing.T) {
func TestRollingUpgradeForDeploymentWithSecret(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy")
config := Config{
namespace: namespace,
resourceName: secretName,
shaValue: shaData,
annotation: constants.SecretUpdateOnChangeAnnotation,
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
deploymentFuncs := RollingUpgradeFuncs{
ItemsFunc: GetDeploymentItems,
ContainersFunc: GetDeploymentContainers,
UpdateFunc: UpdateDeployment,
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceTypeFunc: callbacks.GetDeploymentTypeName,
}
err := PerformRollingUpgrade(client, config, constants.SecretEnvarPostfix, deploymentFuncs)
err := PerformRollingUpgrade(client, config, constants.SecretEnvVarPostfix, 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.VerifyDeploymentUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
if !updated {
t.Errorf("Deployment was not updated")
}
@@ -207,26 +200,27 @@ func TestRollingUpgradeForDeploymentWithSecret(t *testing.T) {
func TestRollingUpgradeForDaemonSetWithConfigmap(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.facebook.com")
config := Config{
namespace: namespace,
resourceName: configmapName,
shaValue: shaData,
annotation: constants.ConfigmapUpdateOnChangeAnnotation,
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
daemonSetFuncs := RollingUpgradeFuncs{
ItemsFunc: GetDaemonSetItems,
ContainersFunc: GetDaemonSetContainers,
UpdateFunc: UpdateDaemonSet,
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceTypeFunc: callbacks.GetDaemonSetTypeName,
}
err := PerformRollingUpgrade(client, config, constants.ConfigmapEnvarPostfix, daemonSetFuncs)
err := PerformRollingUpgrade(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
time.Sleep(5 * time.Second)
if err != nil {
t.Errorf("Rolling upgrade failed for DaemonSet with configmap")
}
logrus.Infof("Verifying daemonSet update")
updated := testutil.VerifyDaemonSetUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
}
@@ -235,26 +229,27 @@ func TestRollingUpgradeForDaemonSetWithConfigmap(t *testing.T) {
func TestRollingUpgradeForDaemonSetWithSecret(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "d3d3LmZhY2Vib29rLmNvbQ==")
config := Config{
namespace: namespace,
resourceName: secretName,
shaValue: shaData,
annotation: constants.SecretUpdateOnChangeAnnotation,
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
daemonSetFuncs := RollingUpgradeFuncs{
ItemsFunc: GetDaemonSetItems,
ContainersFunc: GetDaemonSetContainers,
UpdateFunc: UpdateDaemonSet,
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceTypeFunc: callbacks.GetDaemonSetTypeName,
}
err := PerformRollingUpgrade(client, config, constants.SecretEnvarPostfix, daemonSetFuncs)
err := PerformRollingUpgrade(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
time.Sleep(5 * time.Second)
if err != nil {
t.Errorf("Rolling upgrade failed for DaemonSet with secret")
}
logrus.Infof("Verifying daemonSet update")
updated := testutil.VerifyDaemonSetUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
}
@@ -263,26 +258,27 @@ func TestRollingUpgradeForDaemonSetWithSecret(t *testing.T) {
func TestRollingUpgradeForStatefulSetWithConfigmap(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.twitter.com")
config := Config{
namespace: namespace,
resourceName: configmapName,
shaValue: shaData,
annotation: constants.ConfigmapUpdateOnChangeAnnotation,
config := util.Config{
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
statefulSetFuncs := RollingUpgradeFuncs{
ItemsFunc: GetStatefulSetItems,
ContainersFunc: GetStatefulsetContainers,
UpdateFunc: UpdateStatefulset,
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceTypeFunc: callbacks.GetStatefulSetTypeName,
}
err := PerformRollingUpgrade(client, config, constants.ConfigmapEnvarPostfix, statefulSetFuncs)
err := PerformRollingUpgrade(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
time.Sleep(5 * time.Second)
if err != nil {
t.Errorf("Rolling upgrade failed for StatefulSet with configmap")
}
logrus.Infof("Verifying statefulSet update")
updated := testutil.VerifyStatefulSetUpdate(client, namespace, configmapName, constants.ConfigmapEnvarPostfix, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")
}
@@ -291,26 +287,27 @@ func TestRollingUpgradeForStatefulSetWithConfigmap(t *testing.T) {
func TestRollingUpgradeForStatefulSetWithSecret(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "d3d3LnR3aXR0ZXIuY29t")
config := Config{
namespace: namespace,
resourceName: secretName,
shaValue: shaData,
annotation: constants.SecretUpdateOnChangeAnnotation,
config := util.Config{
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
statefulSetFuncs := RollingUpgradeFuncs{
ItemsFunc: GetStatefulSetItems,
ContainersFunc: GetStatefulsetContainers,
UpdateFunc: UpdateStatefulset,
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceTypeFunc: callbacks.GetStatefulSetTypeName,
}
err := PerformRollingUpgrade(client, config, constants.SecretEnvarPostfix, statefulSetFuncs)
err := PerformRollingUpgrade(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
time.Sleep(5 * time.Second)
if err != nil {
t.Errorf("Rolling upgrade failed for StatefulSet with secret")
}
logrus.Infof("Verifying statefulSet update")
updated := testutil.VerifyStatefulSetUpdate(client, namespace, secretName, constants.SecretEnvarPostfix, shaData, constants.SecretUpdateOnChangeAnnotation)
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")
}
+53 -97
View File
@@ -1,14 +1,17 @@
package testutil
import (
"math/rand"
"sort"
"strings"
"time"
"github.com/sirupsen/logrus"
"github.com/stakater/Reloader/internal/pkg/common"
"github.com/stakater/Reloader/internal/pkg/callbacks"
"github.com/stakater/Reloader/internal/pkg/constants"
"github.com/stakater/Reloader/internal/pkg/crypto"
"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"
"k8s.io/api/extensions/v1beta1"
@@ -18,12 +21,21 @@ import (
)
var (
letters = []rune("abcdefghijklmnopqrstuvwxyz")
// ConfigmapResourceType is a resource type which controller watches for changes
ConfigmapResourceType = "configMaps"
// SecretResourceType is a resource type which controller watches for changes
SecretResourceType = "secrets"
)
func GetClient() *kubernetes.Clientset {
newClient, err := kube.GetClient()
if err != nil {
logrus.Fatalf("Unable to create Kubernetes client error = %v", err)
}
return newClient
}
// CreateNamespace creates namespace for testing
func CreateNamespace(namespace string, client kubernetes.Interface) {
_, err := client.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}})
@@ -208,102 +220,8 @@ func GetSecretWithUpdatedLabel(namespace string, secretName string, label string
}
}
// VerifyDeploymentUpdate verifies whether deployment has been updated with environment variable or not
func VerifyDeploymentUpdate(client kubernetes.Interface, namespace string, name string, envarPostfix string, shaData string, annotation 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[annotation]
if annotationValue != "" {
values := strings.Split(annotationValue, ",")
matches := false
for _, value := range values {
if value == name {
matches = true
break
}
}
if matches {
envName := constants.EnvVarPrefix + common.ConvertToEnvVarName(annotationValue) + envarPostfix
updated := getResourceSHA(containers, envName)
if updated == shaData {
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, annotation 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[annotation]
if annotationValue != "" {
values := strings.Split(annotationValue, ",")
matches := false
for _, value := range values {
if value == name {
matches = true
break
}
}
if matches {
envName := constants.EnvVarPrefix + common.ConvertToEnvVarName(annotationValue) + resourceType
updated := getResourceSHA(containers, envName)
if updated == shaData {
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, annotation 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[annotation]
if annotationValue != "" {
values := strings.Split(annotationValue, ",")
matches := false
for _, value := range values {
if value == name {
matches = true
break
}
}
if matches {
envName := constants.EnvVarPrefix + common.ConvertToEnvVarName(annotationValue) + resourceType
updated := getResourceSHA(containers, envName)
if updated == shaData {
return true
}
}
}
}
return false
}
func getResourceSHA(containers []v1.Container, envar string) string {
// GetResourceSHA returns the SHA value of given environment variable
func GetResourceSHA(containers []v1.Container, envar string) string {
for i := range containers {
envs := containers[i].Env
for j := range envs {
@@ -446,3 +364,41 @@ func DeleteSecret(client kubernetes.Interface, namespace string, secretName stri
time.Sleep(5 * time.Second)
return err
}
// 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)
}
func VerifyResourceUpdate(client kubernetes.Interface, config util.Config, envVarPostfix string, upgradeFuncs callbacks.RollingUpgradeFuncs) bool {
items := upgradeFuncs.ItemsFunc(client, config.Namespace)
for _, i := range items {
containers := upgradeFuncs.ContainersFunc(i)
// match statefulsets with the correct annotation
annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation]
if annotationValue != "" {
values := strings.Split(annotationValue, ",")
matches := false
for _, value := range values {
if value == config.ResourceName {
matches = true
break
}
}
if matches {
envName := constants.EnvVarPrefix + util.ConvertToEnvVarName(annotationValue) + envVarPostfix
updated := GetResourceSHA(containers, envName)
if updated == config.SHAValue {
return true
}
}
}
}
return false
}
+9
View File
@@ -0,0 +1,9 @@
package util
//Config contains rolling upgrade configuration parameters
type Config struct {
Namespace string
ResourceName string
Annotation string
SHAValue string
}
@@ -1,14 +1,8 @@
package common
package util
import (
"bytes"
"math/rand"
"strings"
"time"
)
var (
letters = []rune("abcdefghijklmnopqrstuvwxyz")
)
// ConvertToEnvVarName converts the given text into a usable env var
@@ -31,13 +25,3 @@ func ConvertToEnvVarName(text string) string {
}
return buffer.String()
}
// 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)
}
@@ -1,4 +1,4 @@
package common
package util
import (
"testing"
@@ -11,11 +11,3 @@ func TestConvertToEnvVarName(t *testing.T) {
t.Errorf("Failed to convert data into environment variable")
}
}
func TestRandSeq(t *testing.T) {
data := RandSeq(5)
newData := RandSeq(5)
if data == newData {
t.Errorf("Random sequence generator does not work correctly")
}
}