mirror of
https://github.com/stakater/Reloader.git
synced 2026-02-14 18:09:50 +00:00
Auto update referenced resource (#45)
* Add implementation for create event Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Add sleep in testcase Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Fix test case data Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Remove unnecessary dashes from chart Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Fix new env var creation issue Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Optimize upgrade code Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Update logs Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Initial implementation to perform rolling upgrades by auto referencing the resources Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Fix nil pointer exception Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Fix test cases Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Add test cases Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Update test case verify method Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Add missing name for envs Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Update annotation name Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Update readme Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Update readme Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Implement Golang CI comment Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com> * Implement Golang CI comment Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
This commit is contained in:
committed by
Rasheed Amir
parent
cd19d739ab
commit
130741480e
24
README.md
24
README.md
@@ -21,8 +21,27 @@ Reloader can watch changes in `ConfigMap` and `Secret` and do rolling upgrades o
|
||||
|
||||
## How to use Reloader
|
||||
|
||||
For a `Deployment` called `foo` have a `ConfigMap` called `foo-configmap` or `Secret` called `foo-secret` or both. Then add this annotation to main metadata of your `Deployment`
|
||||
|
||||
```yaml
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
reloader.stakater.com/auto: "true"
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
```
|
||||
|
||||
This will discover deployments/daemonsets/statefulset automatically where `foo-configmap` or `foo-secret` is being used either via environment variable or from volume mount. And it will perform rolling upgrade on related pods when `foo-configmap` or `foo-secret`are updated.
|
||||
|
||||
We can also specify a specific configmap or secret which would trigger rolling upgrade only upon change in our specified configmap or secret, this way, it will not trigger rolling upgrade upon changes in all configmaps or secrets used in a deployment, daemonset or statefulset.
|
||||
To do this either set `reloader.stakater.com/auto: "false"` or remove this annotation altogather, and use annotations mentioned [here](#Configmap) or [here](#Secret)
|
||||
|
||||
### Configmap
|
||||
|
||||
To perform rolling upgrade when change happens only on specific configmaps use below annotation.
|
||||
|
||||
For a `Deployment` called `foo` have a `ConfigMap` called `foo-configmap`. Then add this annotation to main metadata of your `Deployment`
|
||||
|
||||
```yaml
|
||||
@@ -49,6 +68,8 @@ spec:
|
||||
|
||||
### Secret
|
||||
|
||||
To perform rolling upgrade when change happens only on specific secrets use below annotation.
|
||||
|
||||
For a `Deployment` called `foo` have a `Secret` called `foo-secret`. Then add this annotation to main metadata of your `Deployment`
|
||||
|
||||
```yaml
|
||||
@@ -73,6 +94,9 @@ spec:
|
||||
metadata:
|
||||
```
|
||||
|
||||
### NOTE
|
||||
`reloader.stakater.com/auto: "true"` will always override when use with either `secret.reloader.stakater.com/reload` or `configmap.reloader.stakater.com/reload` annotation.
|
||||
|
||||
## Deploying to Kubernetes
|
||||
|
||||
You can deploy Reloader by following methods:
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
---
|
||||
{{- if and .Values.reloader.watchGlobally (.Values.reloader.rbac.enabled) }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{{- if and .Values.reloader.watchGlobally (.Values.reloader.rbac.enabled) }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{{- if and (not (.Values.reloader.watchGlobally)) (.Values.reloader.rbac.enabled) }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
|
||||
@@ -16,6 +16,9 @@ type ItemsFunc func(kubernetes.Interface, string) []interface{}
|
||||
//ContainersFunc is a generic func to return containers
|
||||
type ContainersFunc func(interface{}) []v1.Container
|
||||
|
||||
//VolumesFunc is a generic func to return volumes
|
||||
type VolumesFunc func(interface{}) []v1.Volume
|
||||
|
||||
//UpdateFunc performs the resource update
|
||||
type UpdateFunc func(kubernetes.Interface, string, interface{}) error
|
||||
|
||||
@@ -24,6 +27,7 @@ type RollingUpgradeFuncs struct {
|
||||
ItemsFunc ItemsFunc
|
||||
ContainersFunc ContainersFunc
|
||||
UpdateFunc UpdateFunc
|
||||
VolumesFunc VolumesFunc
|
||||
ResourceType string
|
||||
}
|
||||
|
||||
@@ -89,3 +93,18 @@ func UpdateStatefulset(client kubernetes.Interface, namespace string, resource i
|
||||
_, err := client.AppsV1beta1().StatefulSets(namespace).Update(&statefulSet)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetDeploymentVolumes returns the Volumes of given deployment
|
||||
func GetDeploymentVolumes(item interface{}) []v1.Volume {
|
||||
return item.(v1beta1.Deployment).Spec.Template.Spec.Volumes
|
||||
}
|
||||
|
||||
// GetDaemonSetVolumes returns the Volumes of given daemonset
|
||||
func GetDaemonSetVolumes(item interface{}) []v1.Volume {
|
||||
return item.(v1beta1.DaemonSet).Spec.Template.Spec.Volumes
|
||||
}
|
||||
|
||||
// GetStatefulsetVolumes returns the Volumes of given statefulSet
|
||||
func GetStatefulsetVolumes(item interface{}) []v1.Volume {
|
||||
return item.(apps_v1beta1.StatefulSet).Spec.Template.Spec.Volumes
|
||||
}
|
||||
|
||||
@@ -5,4 +5,6 @@ const (
|
||||
ConfigmapUpdateOnChangeAnnotation = "configmap.reloader.stakater.com/reload"
|
||||
// SecretUpdateOnChangeAnnotation is an annotation to detect changes in secrets
|
||||
SecretUpdateOnChangeAnnotation = "secret.reloader.stakater.com/reload"
|
||||
// ReloaderAutoAnnotation is an annotation to detect changes in secrets
|
||||
ReloaderAutoAnnotation = "reloader.stakater.com/auto"
|
||||
)
|
||||
|
||||
15
internal/pkg/constants/enums.go
Normal file
15
internal/pkg/constants/enums.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package constants
|
||||
|
||||
// Result is a status for deployment update
|
||||
type Result int
|
||||
|
||||
const (
|
||||
// Updated is returned when environment variable is created/updated
|
||||
Updated Result = 1 + iota
|
||||
// NotUpdated is returned when environment variable is found but had value equals to the new value
|
||||
NotUpdated
|
||||
// NoEnvVarFound is returned when no environment variable is found
|
||||
NoEnvVarFound
|
||||
// NoContainerFound is returned when no environment variable is found
|
||||
NoContainerFound
|
||||
)
|
||||
@@ -64,7 +64,7 @@ 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{}) {
|
||||
logrus.Infof("Resource deletion has been detected but no further implementation found to take action")
|
||||
// Todo: Any future delete event can be handled here
|
||||
}
|
||||
|
||||
//Run function for controller which handles the queue
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/callbacks"
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/handler"
|
||||
"github.com/stakater/Reloader/internal/pkg/testutil"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
"github.com/stakater/Reloader/pkg/kube"
|
||||
@@ -60,7 +60,7 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDeployment(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace)
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in deployment creation: %v", err)
|
||||
}
|
||||
@@ -80,12 +80,120 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDeployment(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
ResourceType: "Deployment",
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// Deleting deployment
|
||||
err = testutil.DeleteDeployment(client, namespace, configmapName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the deployment %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 deployment and create env var upon updating the configmap
|
||||
func TestControllerUpdatingConfigmapShouldAutoCreateEnvInDeployment(t *testing.T) {
|
||||
|
||||
// Creating configmap
|
||||
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)
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error in deployment creation: %v", err)
|
||||
}
|
||||
|
||||
// Updating configmap for first time
|
||||
updateErr := testutil.UpdateConfigMap(configmapClient, namespace, configmapName, "", "www.stakater.com")
|
||||
if updateErr != nil {
|
||||
t.Errorf("Configmap was not updated")
|
||||
}
|
||||
|
||||
// Verifying deployment update
|
||||
logrus.Infof("Verifying env var has been created")
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.stakater.com")
|
||||
config := util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: configmapName,
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// Deleting deployment
|
||||
err = testutil.DeleteDeployment(client, namespace, configmapName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the deployment %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 deployment and create env var upon creating the configmap
|
||||
func TestControllerCreatingConfigmapShouldCreateEnvInDeployment(t *testing.T) {
|
||||
|
||||
// Creating configmap
|
||||
configmapName := configmapNamePrefix + "-create-" + testutil.RandSeq(5)
|
||||
_, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
|
||||
if err != nil {
|
||||
t.Errorf("Error while creating the configmap %v", err)
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in deployment creation: %v", err)
|
||||
}
|
||||
|
||||
// Deleting configmap for first time
|
||||
err = testutil.DeleteConfigMap(client, namespace, configmapName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the configmap %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
_, err = testutil.CreateConfigMap(client, namespace, configmapName, "www.stakater.com")
|
||||
if err != nil {
|
||||
t.Errorf("Error while creating the configmap second time %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// Verifying deployment update
|
||||
logrus.Infof("Verifying env var has been created")
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.stakater.com")
|
||||
config := util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: configmapName,
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
@@ -116,7 +224,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace)
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in deployment creation: %v", err)
|
||||
}
|
||||
@@ -143,12 +251,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
|
||||
deploymentFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
ResourceType: "Deployment",
|
||||
}
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
@@ -180,7 +283,7 @@ func TestControllerUpdatingConfigmapLabelsShouldNotCreateorUpdateEnvInDeployment
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace)
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in deployment creation: %v", err)
|
||||
}
|
||||
@@ -200,12 +303,7 @@ func TestControllerUpdatingConfigmapLabelsShouldNotCreateorUpdateEnvInDeployment
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
ResourceType: "Deployment",
|
||||
}
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if updated {
|
||||
t.Errorf("Deployment should not be updated by changing label")
|
||||
@@ -226,7 +324,66 @@ func TestControllerUpdatingConfigmapLabelsShouldNotCreateorUpdateEnvInDeployment
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
// Perform rolling upgrade on secret and create a env var upon updating the secret
|
||||
// Perform rolling upgrade on pod and create a env var upon creating the secret
|
||||
func TestControllerCreatingSecretShouldCreateEnvInDeployment(t *testing.T) {
|
||||
// Creating secret
|
||||
secretName := secretNamePrefix + "-create-" + testutil.RandSeq(5)
|
||||
_, err := testutil.CreateSecret(client, namespace, secretName, data)
|
||||
if err != nil {
|
||||
t.Errorf("Error in secret creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in deployment creation: %v", err)
|
||||
}
|
||||
|
||||
//Deleting Secret
|
||||
err = testutil.DeleteSecret(client, namespace, secretName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the secret %v", err)
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
_, err = testutil.CreateSecret(client, namespace, secretName, newData)
|
||||
if err != nil {
|
||||
t.Errorf("Error in secret creation: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// Verifying Upgrade
|
||||
logrus.Infof("Verifying env var has been created")
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, newData)
|
||||
config := util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: secretName,
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
time.Sleep(5 * time.Second)
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
}
|
||||
|
||||
// Deleting Deployment
|
||||
err = testutil.DeleteDeployment(client, namespace, secretName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the deployment %v", err)
|
||||
}
|
||||
|
||||
//Deleting Secret
|
||||
err = testutil.DeleteSecret(client, namespace, secretName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the secret %v", err)
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
// Perform rolling upgrade on pod and create a env var upon updating the secret
|
||||
func TestControllerUpdatingSecretShouldCreateEnvInDeployment(t *testing.T) {
|
||||
// Creating secret
|
||||
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
|
||||
@@ -236,7 +393,7 @@ func TestControllerUpdatingSecretShouldCreateEnvInDeployment(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(client, secretName, namespace)
|
||||
_, err = testutil.CreateDeployment(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in deployment creation: %v", err)
|
||||
}
|
||||
@@ -256,12 +413,7 @@ func TestControllerUpdatingSecretShouldCreateEnvInDeployment(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
ResourceType: "Deployment",
|
||||
}
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
@@ -291,7 +443,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDeployment(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(client, secretName, namespace)
|
||||
_, err = testutil.CreateDeployment(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in deployment creation: %v", err)
|
||||
}
|
||||
@@ -317,12 +469,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDeployment(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
ResourceType: "Deployment",
|
||||
}
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
@@ -342,7 +489,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDeployment(t *testing.T) {
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
// Do not Perform rolling upgrade on secret and create or update a env var upon updating the label in secret
|
||||
// Do not Perform rolling upgrade on pod and create or update a env var upon updating the label in secret
|
||||
func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDeployment(t *testing.T) {
|
||||
// Creating secret
|
||||
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
|
||||
@@ -352,7 +499,7 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDeployment(t
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(client, secretName, namespace)
|
||||
_, err = testutil.CreateDeployment(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in deployment creation: %v", err)
|
||||
}
|
||||
@@ -371,12 +518,7 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDeployment(t
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
ResourceType: "Deployment",
|
||||
}
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
|
||||
if updated {
|
||||
t.Errorf("Deployment should not be updated by changing label in secret")
|
||||
@@ -406,7 +548,7 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDaemonSet(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating DaemonSet
|
||||
_, err = testutil.CreateDaemonSet(client, configmapName, namespace)
|
||||
_, err = testutil.CreateDaemonSet(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in DaemonSet creation: %v", err)
|
||||
}
|
||||
@@ -426,12 +568,7 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDaemonSet(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDaemonSetItems,
|
||||
ContainersFunc: callbacks.GetDaemonSetContainers,
|
||||
UpdateFunc: callbacks.UpdateDaemonSet,
|
||||
ResourceType: "DaemonSet",
|
||||
}
|
||||
daemonSetFuncs := handler.GetDaemonSetRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("DaemonSet was not updated")
|
||||
@@ -462,7 +599,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateDaemonSet(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating DaemonSet
|
||||
_, err = testutil.CreateDaemonSet(client, configmapName, namespace)
|
||||
_, err = testutil.CreateDaemonSet(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in DaemonSet creation: %v", err)
|
||||
}
|
||||
@@ -473,12 +610,16 @@ func TestControllerForUpdatingConfigmapShouldUpdateDaemonSet(t *testing.T) {
|
||||
t.Errorf("Configmap was not updated")
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// Updating configmap for second time
|
||||
updateErr = testutil.UpdateConfigMap(configmapClient, namespace, configmapName, "", "aurorasolutions.io")
|
||||
if updateErr != nil {
|
||||
t.Errorf("Configmap was not updated")
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// Verifying DaemonSet update
|
||||
logrus.Infof("Verifying env var has been updated")
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "aurorasolutions.io")
|
||||
@@ -488,12 +629,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateDaemonSet(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDaemonSetItems,
|
||||
ContainersFunc: callbacks.GetDaemonSetContainers,
|
||||
UpdateFunc: callbacks.UpdateDaemonSet,
|
||||
ResourceType: "DaemonSet",
|
||||
}
|
||||
daemonSetFuncs := handler.GetDaemonSetRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("DaemonSet was not updated")
|
||||
@@ -514,7 +650,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateDaemonSet(t *testing.T) {
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
// Perform rolling upgrade on secret and create a env var upon updating the secret
|
||||
// Perform rolling upgrade on pod and create a env var upon updating the secret
|
||||
func TestControllerUpdatingSecretShouldCreateEnvInDaemonSet(t *testing.T) {
|
||||
// Creating secret
|
||||
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
|
||||
@@ -524,7 +660,7 @@ func TestControllerUpdatingSecretShouldCreateEnvInDaemonSet(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating DaemonSet
|
||||
_, err = testutil.CreateDaemonSet(client, secretName, namespace)
|
||||
_, err = testutil.CreateDaemonSet(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in DaemonSet creation: %v", err)
|
||||
}
|
||||
@@ -544,12 +680,7 @@ func TestControllerUpdatingSecretShouldCreateEnvInDaemonSet(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDaemonSetItems,
|
||||
ContainersFunc: callbacks.GetDaemonSetContainers,
|
||||
UpdateFunc: callbacks.UpdateDaemonSet,
|
||||
ResourceType: "DaemonSet",
|
||||
}
|
||||
daemonSetFuncs := handler.GetDaemonSetRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("DaemonSet was not updated")
|
||||
@@ -579,7 +710,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDaemonSet(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating DaemonSet
|
||||
_, err = testutil.CreateDaemonSet(client, secretName, namespace)
|
||||
_, err = testutil.CreateDaemonSet(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in DaemonSet creation: %v", err)
|
||||
}
|
||||
@@ -606,12 +737,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDaemonSet(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDaemonSetItems,
|
||||
ContainersFunc: callbacks.GetDaemonSetContainers,
|
||||
UpdateFunc: callbacks.UpdateDaemonSet,
|
||||
ResourceType: "DaemonSet",
|
||||
}
|
||||
daemonSetFuncs := handler.GetDaemonSetRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("DaemonSet was not updated")
|
||||
@@ -631,7 +757,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDaemonSet(t *testing.T) {
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
// Do not Perform rolling upgrade on secret and create or update a env var upon updating the label in secret
|
||||
// Do not Perform rolling upgrade on pod and create or update a env var upon updating the label in secret
|
||||
func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDaemonSet(t *testing.T) {
|
||||
// Creating secret
|
||||
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
|
||||
@@ -641,7 +767,7 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDaemonSet(t *
|
||||
}
|
||||
|
||||
// Creating DaemonSet
|
||||
_, err = testutil.CreateDaemonSet(client, secretName, namespace)
|
||||
_, err = testutil.CreateDaemonSet(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in DaemonSet creation: %v", err)
|
||||
}
|
||||
@@ -660,12 +786,7 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDaemonSet(t *
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDaemonSetItems,
|
||||
ContainersFunc: callbacks.GetDaemonSetContainers,
|
||||
UpdateFunc: callbacks.UpdateDaemonSet,
|
||||
ResourceType: "DaemonSet",
|
||||
}
|
||||
daemonSetFuncs := handler.GetDaemonSetRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
|
||||
if updated {
|
||||
t.Errorf("DaemonSet should not be updated by changing label in secret")
|
||||
@@ -695,7 +816,7 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInStatefulSet(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating StatefulSet
|
||||
_, err = testutil.CreateStatefulSet(client, configmapName, namespace)
|
||||
_, err = testutil.CreateStatefulSet(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in StatefulSet creation: %v", err)
|
||||
}
|
||||
@@ -715,12 +836,7 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInStatefulSet(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetStatefulSetItems,
|
||||
ContainersFunc: callbacks.GetStatefulsetContainers,
|
||||
UpdateFunc: callbacks.UpdateStatefulset,
|
||||
ResourceType: "StatefulSet",
|
||||
}
|
||||
statefulSetFuncs := handler.GetStatefulSetRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("StatefulSet was not updated")
|
||||
@@ -751,7 +867,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateStatefulSet(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating StatefulSet
|
||||
_, err = testutil.CreateStatefulSet(client, configmapName, namespace)
|
||||
_, err = testutil.CreateStatefulSet(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in StatefulSet creation: %v", err)
|
||||
}
|
||||
@@ -777,12 +893,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateStatefulSet(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetStatefulSetItems,
|
||||
ContainersFunc: callbacks.GetStatefulsetContainers,
|
||||
UpdateFunc: callbacks.UpdateStatefulset,
|
||||
ResourceType: "StatefulSet",
|
||||
}
|
||||
statefulSetFuncs := handler.GetStatefulSetRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("StatefulSet was not updated")
|
||||
@@ -803,7 +914,7 @@ func TestControllerForUpdatingConfigmapShouldUpdateStatefulSet(t *testing.T) {
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
// Perform rolling upgrade on secret and create a env var upon updating the secret
|
||||
// Perform rolling upgrade on pod and create a env var upon updating the secret
|
||||
func TestControllerUpdatingSecretShouldCreateEnvInStatefulSet(t *testing.T) {
|
||||
// Creating secret
|
||||
secretName := secretNamePrefix + "-update-" + testutil.RandSeq(5)
|
||||
@@ -813,7 +924,7 @@ func TestControllerUpdatingSecretShouldCreateEnvInStatefulSet(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating StatefulSet
|
||||
_, err = testutil.CreateStatefulSet(client, secretName, namespace)
|
||||
_, err = testutil.CreateStatefulSet(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in StatefulSet creation: %v", err)
|
||||
}
|
||||
@@ -833,12 +944,7 @@ func TestControllerUpdatingSecretShouldCreateEnvInStatefulSet(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetStatefulSetItems,
|
||||
ContainersFunc: callbacks.GetStatefulsetContainers,
|
||||
UpdateFunc: callbacks.UpdateStatefulset,
|
||||
ResourceType: "StatefulSet",
|
||||
}
|
||||
statefulSetFuncs := handler.GetStatefulSetRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("StatefulSet was not updated")
|
||||
@@ -868,7 +974,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInStatefulSet(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creating StatefulSet
|
||||
_, err = testutil.CreateStatefulSet(client, secretName, namespace)
|
||||
_, err = testutil.CreateStatefulSet(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error in StatefulSet creation: %v", err)
|
||||
}
|
||||
@@ -894,12 +1000,7 @@ func TestControllerUpdatingSecretShouldUpdateEnvInStatefulSet(t *testing.T) {
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetStatefulSetItems,
|
||||
ContainersFunc: callbacks.GetStatefulsetContainers,
|
||||
UpdateFunc: callbacks.UpdateStatefulset,
|
||||
ResourceType: "StatefulSet",
|
||||
}
|
||||
statefulSetFuncs := handler.GetStatefulSetRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("StatefulSet was not updated")
|
||||
|
||||
@@ -2,6 +2,8 @@ package handler
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// ResourceCreatedHandler contains new objects
|
||||
@@ -13,6 +15,25 @@ type ResourceCreatedHandler struct {
|
||||
func (r ResourceCreatedHandler) Handle() error {
|
||||
if r.Resource == nil {
|
||||
logrus.Errorf("Resource creation handler received nil resource")
|
||||
} else {
|
||||
config, _ := r.GetConfig()
|
||||
logrus.Infof("Resource '%s' of type '%s' in namespace '%s' has been created", config.ResourceName, config.Type, config.Namespace)
|
||||
// process resource based on its type
|
||||
doRollingUpgrade(config)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetConfig gets configurations containing SHA, annotations, namespace and resource name
|
||||
func (r ResourceCreatedHandler) GetConfig() (util.Config, string) {
|
||||
var oldSHAData string
|
||||
var config util.Config
|
||||
if _, ok := r.Resource.(*v1.ConfigMap); ok {
|
||||
config = util.GetConfigmapConfig(r.Resource.(*v1.ConfigMap))
|
||||
} else if _, ok := r.Resource.(*v1.Secret); ok {
|
||||
config = util.GetSecretConfig(r.Resource.(*v1.Secret))
|
||||
} else {
|
||||
logrus.Warnf("Invalid resource: Resource should be 'Secret' or 'Configmap' but found, %v", r.Resource)
|
||||
}
|
||||
return config, oldSHAData
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
)
|
||||
|
||||
// ResourceHandler handles the creation and update of resources
|
||||
type ResourceHandler interface {
|
||||
Handle() error
|
||||
GetConfig() (util.Config, string)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"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"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// ResourceUpdatedHandler contains updated objects
|
||||
@@ -25,162 +17,28 @@ func (r ResourceUpdatedHandler) Handle() error {
|
||||
if r.Resource == nil || r.OldResource == nil {
|
||||
logrus.Errorf("Resource update handler received nil resource")
|
||||
} else {
|
||||
config, envVarPostfix, oldSHAData := getConfig(r)
|
||||
config, oldSHAData := r.GetConfig()
|
||||
if config.SHAValue != oldSHAData {
|
||||
logrus.Infof("Changes detected in %s of type '%s' in namespace: %s", config.ResourceName, envVarPostfix, config.Namespace)
|
||||
logrus.Infof("Changes detected in '%s' of type '%s' in namespace '%s'", config.ResourceName, config.Type, config.Namespace)
|
||||
// process resource based on its type
|
||||
rollingUpgrade(r, config, envVarPostfix, callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
ResourceType: "Deployment",
|
||||
})
|
||||
rollingUpgrade(r, config, envVarPostfix, callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDaemonSetItems,
|
||||
ContainersFunc: callbacks.GetDaemonSetContainers,
|
||||
UpdateFunc: callbacks.UpdateDaemonSet,
|
||||
ResourceType: "DaemonSet",
|
||||
})
|
||||
rollingUpgrade(r, config, envVarPostfix, callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetStatefulSetItems,
|
||||
ContainersFunc: callbacks.GetStatefulsetContainers,
|
||||
UpdateFunc: callbacks.UpdateStatefulset,
|
||||
ResourceType: "StatefulSet",
|
||||
})
|
||||
doRollingUpgrade(config)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func rollingUpgrade(r ResourceUpdatedHandler, config util.Config, envarPostfix string, upgradeFuncs callbacks.RollingUpgradeFuncs) {
|
||||
client, err := kube.GetClient()
|
||||
if err != nil {
|
||||
logrus.Fatalf("Unable to create Kubernetes client error = %v", err)
|
||||
}
|
||||
|
||||
err = PerformRollingUpgrade(client, config, envarPostfix, upgradeFuncs)
|
||||
if err != nil {
|
||||
logrus.Errorf("Rolling upgrade for %s failed with error = %v", config.ResourceName, err)
|
||||
}
|
||||
}
|
||||
|
||||
func getConfig(r ResourceUpdatedHandler) (util.Config, string, string) {
|
||||
var oldSHAData, envVarPostfix string
|
||||
// GetConfig gets configurations containing SHA, annotations, namespace and resource name
|
||||
func (r ResourceUpdatedHandler) GetConfig() (util.Config, string) {
|
||||
var oldSHAData string
|
||||
var config util.Config
|
||||
if _, ok := r.Resource.(*v1.ConfigMap); ok {
|
||||
oldSHAData = getSHAfromConfigmap(r.OldResource.(*v1.ConfigMap).Data)
|
||||
config = getConfigmapConfig(r)
|
||||
envVarPostfix = constants.ConfigmapEnvVarPostfix
|
||||
oldSHAData = util.GetSHAfromConfigmap(r.OldResource.(*v1.ConfigMap).Data)
|
||||
config = util.GetConfigmapConfig(r.Resource.(*v1.ConfigMap))
|
||||
} else if _, ok := r.Resource.(*v1.Secret); ok {
|
||||
oldSHAData = getSHAfromSecret(r.OldResource.(*v1.Secret).Data)
|
||||
config = getSecretConfig(r)
|
||||
envVarPostfix = constants.SecretEnvVarPostfix
|
||||
oldSHAData = util.GetSHAfromSecret(r.OldResource.(*v1.Secret).Data)
|
||||
config = util.GetSecretConfig(r.Resource.(*v1.Secret))
|
||||
} 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 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)
|
||||
resourceName := util.ToObjectMeta(i).Name
|
||||
// find correct annotation and update the resource
|
||||
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 !updated {
|
||||
logrus.Warnf("Rolling upgrade failed because no container found to add environment variable in %s of type %s in namespace: %s", resourceName, upgradeFuncs.ResourceType, config.Namespace)
|
||||
} else {
|
||||
err = upgradeFuncs.UpdateFunc(client, config.Namespace, i)
|
||||
if err != nil {
|
||||
logrus.Errorf("Update for %s of type %s in namespace %s failed with error %v", resourceName, upgradeFuncs.ResourceType, config.Namespace, err)
|
||||
} else {
|
||||
logrus.Infof("Updated %s of type %s in namespace: %s ", resourceName, upgradeFuncs.ResourceType, config.Namespace)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func updateContainers(containers []v1.Container, annotationValue string, shaData string, envarPostfix string) bool {
|
||||
updated := false
|
||||
envar := constants.EnvVarPrefix + util.ConvertToEnvVarName(annotationValue)+ "_" + envarPostfix
|
||||
for i := range containers {
|
||||
envs := containers[i].Env
|
||||
|
||||
//update if env var exists
|
||||
updated = updateEnvVar(envs, envar, shaData)
|
||||
|
||||
// if no existing env var exists lets create one
|
||||
if !updated {
|
||||
e := v1.EnvVar{
|
||||
Name: envar,
|
||||
Value: shaData,
|
||||
}
|
||||
containers[i].Env = append(containers[i].Env, e)
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
return updated
|
||||
}
|
||||
|
||||
func updateEnvVar(envs []v1.EnvVar, envar string, shaData string) bool {
|
||||
for j := range envs {
|
||||
if envs[j].Name == envar {
|
||||
if envs[j].Value != shaData {
|
||||
envs[j].Value = shaData
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getSHAfromConfigmap(data map[string]string) string {
|
||||
values := []string{}
|
||||
for k, v := range data {
|
||||
values = append(values, k+"="+v)
|
||||
}
|
||||
sort.Strings(values)
|
||||
return crypto.GenerateSHA(strings.Join(values, ";"))
|
||||
}
|
||||
|
||||
func getSHAfromSecret(data map[string][]byte) string {
|
||||
values := []string{}
|
||||
for k, v := range data {
|
||||
values = append(values, k+"="+string(v[:]))
|
||||
}
|
||||
sort.Strings(values)
|
||||
return crypto.GenerateSHA(strings.Join(values, ";"))
|
||||
return config, oldSHAData
|
||||
}
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"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"
|
||||
testclient "k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
var (
|
||||
client = testclient.NewSimpleClientset()
|
||||
namespace = "test-handler-" + testutil.RandSeq(5)
|
||||
configmapName = "testconfigmap-handler-" + testutil.RandSeq(5)
|
||||
secretName = "testsecret-handler-" + testutil.RandSeq(5)
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
// Creating namespace
|
||||
testutil.CreateNamespace(namespace, client)
|
||||
|
||||
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 setup() {
|
||||
// Creating configmap
|
||||
_, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in configmap creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating secret
|
||||
data := "dGVzdFNlY3JldEVuY29kaW5nRm9yUmVsb2FkZXI="
|
||||
_, err = testutil.CreateSecret(client, namespace, secretName, data)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in secret creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating Deployment with configmap
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in Deployment with configmap creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating Deployment with secret
|
||||
_, err = testutil.CreateDeployment(client, secretName, namespace)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in Deployment with secret creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating DaemonSet with configmap
|
||||
_, err = testutil.CreateDaemonSet(client, configmapName, namespace)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in DaemonSet with configmap creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating DaemonSet with secret
|
||||
_, err = testutil.CreateDaemonSet(client, secretName, namespace)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in DaemonSet with secret creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating StatefulSet with configmap
|
||||
_, err = testutil.CreateStatefulSet(client, configmapName, namespace)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in StatefulSet with configmap creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating StatefulSet with secret
|
||||
_, err = testutil.CreateStatefulSet(client, secretName, namespace)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in StatefulSet with secret creation: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func teardown() {
|
||||
// Deleting Deployment with configmap
|
||||
deploymentError := testutil.DeleteDeployment(client, namespace, configmapName)
|
||||
if deploymentError != nil {
|
||||
logrus.Errorf("Error while deleting deployment with configmap %v", deploymentError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with secret
|
||||
deploymentError = testutil.DeleteDeployment(client, namespace, secretName)
|
||||
if deploymentError != nil {
|
||||
logrus.Errorf("Error while deleting deployment with secret %v", deploymentError)
|
||||
}
|
||||
|
||||
// Deleting DaemonSet with configmap
|
||||
daemonSetError := testutil.DeleteDaemonSet(client, namespace, configmapName)
|
||||
if daemonSetError != nil {
|
||||
logrus.Errorf("Error while deleting daemonSet with configmap %v", daemonSetError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with secret
|
||||
daemonSetError = testutil.DeleteDaemonSet(client, namespace, secretName)
|
||||
if daemonSetError != nil {
|
||||
logrus.Errorf("Error while deleting daemonSet with secret %v", daemonSetError)
|
||||
}
|
||||
|
||||
// Deleting StatefulSet with configmap
|
||||
statefulSetError := testutil.DeleteStatefulSet(client, namespace, configmapName)
|
||||
if statefulSetError != nil {
|
||||
logrus.Errorf("Error while deleting statefulSet with configmap %v", statefulSetError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with secret
|
||||
statefulSetError = testutil.DeleteStatefulSet(client, namespace, secretName)
|
||||
if statefulSetError != nil {
|
||||
logrus.Errorf("Error while deleting statefulSet with secret %v", statefulSetError)
|
||||
}
|
||||
|
||||
// Deleting Configmap
|
||||
err := testutil.DeleteConfigMap(client, namespace, configmapName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the configmap %v", err)
|
||||
}
|
||||
|
||||
// Deleting Secret
|
||||
err = testutil.DeleteSecret(client, namespace, secretName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the secret %v", err)
|
||||
}
|
||||
|
||||
// Deleting namespace
|
||||
testutil.DeleteNamespace(namespace, client)
|
||||
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDeploymentWithConfigmap(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, configmapName, "www.stakater.com")
|
||||
config := util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: configmapName,
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
ResourceType: "Deployment",
|
||||
}
|
||||
|
||||
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.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDeploymentWithSecret(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy")
|
||||
config := util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: secretName,
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
ResourceType: "Deployment",
|
||||
}
|
||||
|
||||
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.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDaemonSetWithConfigmap(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.facebook.com")
|
||||
config := util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: configmapName,
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDaemonSetItems,
|
||||
ContainersFunc: callbacks.GetDaemonSetContainers,
|
||||
UpdateFunc: callbacks.UpdateDaemonSet,
|
||||
ResourceType: "DaemonSet",
|
||||
}
|
||||
|
||||
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.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("DaemonSet was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDaemonSetWithSecret(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "d3d3LmZhY2Vib29rLmNvbQ==")
|
||||
|
||||
config := util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: secretName,
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDaemonSetItems,
|
||||
ContainersFunc: callbacks.GetDaemonSetContainers,
|
||||
UpdateFunc: callbacks.UpdateDaemonSet,
|
||||
ResourceType: "DaemonSet",
|
||||
}
|
||||
|
||||
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.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("DaemonSet was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForStatefulSetWithConfigmap(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.twitter.com")
|
||||
|
||||
config := util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: configmapName,
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetStatefulSetItems,
|
||||
ContainersFunc: callbacks.GetStatefulsetContainers,
|
||||
UpdateFunc: callbacks.UpdateStatefulset,
|
||||
ResourceType: "StatefulSet",
|
||||
}
|
||||
|
||||
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.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("StatefulSet was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForStatefulSetWithSecret(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "d3d3LnR3aXR0ZXIuY29t")
|
||||
|
||||
config := util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: secretName,
|
||||
SHAValue: shaData,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
}
|
||||
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetStatefulSetItems,
|
||||
ContainersFunc: callbacks.GetStatefulsetContainers,
|
||||
UpdateFunc: callbacks.UpdateStatefulset,
|
||||
ResourceType: "StatefulSet",
|
||||
}
|
||||
|
||||
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.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("StatefulSet was not updated")
|
||||
}
|
||||
}
|
||||
191
internal/pkg/handler/upgrade.go
Normal file
191
internal/pkg/handler/upgrade.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/callbacks"
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
"github.com/stakater/Reloader/pkg/kube"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// GetDeploymentRollingUpgradeFuncs returns all callback funcs for a deployment
|
||||
func GetDeploymentRollingUpgradeFuncs() callbacks.RollingUpgradeFuncs {
|
||||
return callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDeploymentItems,
|
||||
ContainersFunc: callbacks.GetDeploymentContainers,
|
||||
UpdateFunc: callbacks.UpdateDeployment,
|
||||
VolumesFunc: callbacks.GetDeploymentVolumes,
|
||||
ResourceType: "Deployment",
|
||||
}
|
||||
}
|
||||
|
||||
// GetDaemonSetRollingUpgradeFuncs returns all callback funcs for a daemonset
|
||||
func GetDaemonSetRollingUpgradeFuncs() callbacks.RollingUpgradeFuncs {
|
||||
return callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetDaemonSetItems,
|
||||
ContainersFunc: callbacks.GetDaemonSetContainers,
|
||||
UpdateFunc: callbacks.UpdateDaemonSet,
|
||||
VolumesFunc: callbacks.GetDaemonSetVolumes,
|
||||
ResourceType: "DaemonSet",
|
||||
}
|
||||
}
|
||||
|
||||
// GetStatefulSetRollingUpgradeFuncs returns all callback funcs for a statefulSet
|
||||
func GetStatefulSetRollingUpgradeFuncs() callbacks.RollingUpgradeFuncs {
|
||||
return callbacks.RollingUpgradeFuncs{
|
||||
ItemsFunc: callbacks.GetStatefulSetItems,
|
||||
ContainersFunc: callbacks.GetStatefulsetContainers,
|
||||
UpdateFunc: callbacks.UpdateStatefulset,
|
||||
VolumesFunc: callbacks.GetStatefulsetVolumes,
|
||||
ResourceType: "StatefulSet",
|
||||
}
|
||||
}
|
||||
|
||||
func doRollingUpgrade(config util.Config) {
|
||||
rollingUpgrade(config, GetDeploymentRollingUpgradeFuncs())
|
||||
rollingUpgrade(config, GetDaemonSetRollingUpgradeFuncs())
|
||||
rollingUpgrade(config, GetStatefulSetRollingUpgradeFuncs())
|
||||
}
|
||||
|
||||
func rollingUpgrade(config util.Config, upgradeFuncs callbacks.RollingUpgradeFuncs) {
|
||||
client, err := kube.GetClient()
|
||||
if err != nil {
|
||||
logrus.Fatalf("Unable to create Kubernetes client error = %v", err)
|
||||
}
|
||||
|
||||
err = PerformRollingUpgrade(client, config, upgradeFuncs)
|
||||
if err != nil {
|
||||
logrus.Errorf("Rolling upgrade for '%s' failed with error = %v", config.ResourceName, err)
|
||||
}
|
||||
}
|
||||
|
||||
// PerformRollingUpgrade upgrades the deployment if there is any change in configmap or secret data
|
||||
func PerformRollingUpgrade(client kubernetes.Interface, config util.Config, upgradeFuncs callbacks.RollingUpgradeFuncs) error {
|
||||
items := upgradeFuncs.ItemsFunc(client, config.Namespace)
|
||||
var err error
|
||||
for _, i := range items {
|
||||
containers := upgradeFuncs.ContainersFunc(i)
|
||||
volumes := upgradeFuncs.VolumesFunc(i)
|
||||
// find correct annotation and update the resource
|
||||
annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation]
|
||||
reloaderEnabledValue := util.ToObjectMeta(i).Annotations[constants.ReloaderAutoAnnotation]
|
||||
if len(containers) > 0 {
|
||||
resourceName := util.ToObjectMeta(i).Name
|
||||
result := constants.NotUpdated
|
||||
reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue)
|
||||
if err == nil && reloaderEnabled {
|
||||
result = updateContainers(volumes, containers, config.ResourceName, config)
|
||||
} else if annotationValue != "" {
|
||||
values := strings.Split(annotationValue, ",")
|
||||
for _, value := range values {
|
||||
if value == config.ResourceName {
|
||||
result = updateContainers(volumes, containers, value, config)
|
||||
if result == constants.Updated {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if result == constants.Updated {
|
||||
err = upgradeFuncs.UpdateFunc(client, config.Namespace, i)
|
||||
if err != nil {
|
||||
logrus.Errorf("Update for '%s' of type '%s' in namespace '%s' failed with error %v", resourceName, upgradeFuncs.ResourceType, config.Namespace, err)
|
||||
} else {
|
||||
logrus.Infof("Updated '%s' of type '%s' in namespace '%s'", resourceName, upgradeFuncs.ResourceType, config.Namespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func getVolumeMountName(volumes []v1.Volume, mountType string, volumeName string) string {
|
||||
for i := range volumes {
|
||||
if mountType == constants.ConfigmapEnvVarPostfix && volumes[i].ConfigMap != nil && volumes[i].ConfigMap.Name == volumeName {
|
||||
return volumes[i].Name
|
||||
} else if mountType == constants.SecretEnvVarPostfix && volumes[i].Secret != nil && volumes[i].Secret.SecretName == volumeName {
|
||||
return volumes[i].Name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getContainerToUpdate(volumes []v1.Volume, containers []v1.Container, envarPostfix string, volumeName string) *v1.Container {
|
||||
// Get the volumeMountName to find volumeMount in container
|
||||
if len(volumes) > 0 {
|
||||
volumeMountName := getVolumeMountName(volumes, envarPostfix, volumeName)
|
||||
// Get the container with mounted configmap/secret
|
||||
if volumeMountName != "" {
|
||||
for i := range containers {
|
||||
volumeMounts := containers[i].VolumeMounts
|
||||
for j := range volumeMounts {
|
||||
if volumeMounts[j].Name == volumeMountName {
|
||||
return &containers[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the container with referenced secret or configmap
|
||||
for i := range containers {
|
||||
envs := containers[i].Env
|
||||
for j := range envs {
|
||||
envVarSource := envs[j].ValueFrom
|
||||
if envVarSource != nil {
|
||||
if envVarSource.SecretKeyRef != nil && envVarSource.SecretKeyRef.LocalObjectReference.Name == volumeName {
|
||||
return &containers[i]
|
||||
} else if envVarSource.ConfigMapKeyRef != nil && envVarSource.ConfigMapKeyRef.LocalObjectReference.Name == volumeName {
|
||||
return &containers[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateContainers(volumes []v1.Volume, containers []v1.Container, annotationValue string, config util.Config) constants.Result {
|
||||
var result constants.Result
|
||||
envar := constants.EnvVarPrefix + util.ConvertToEnvVarName(annotationValue) + "_" + config.Type
|
||||
container := getContainerToUpdate(volumes, containers, config.Type, config.ResourceName)
|
||||
|
||||
if container == nil {
|
||||
return constants.NoContainerFound
|
||||
}
|
||||
|
||||
//update if env var exists
|
||||
result = updateEnvVar(containers, envar, config.SHAValue)
|
||||
|
||||
// if no existing env var exists lets create one
|
||||
if result == constants.NoEnvVarFound {
|
||||
e := v1.EnvVar{
|
||||
Name: envar,
|
||||
Value: config.SHAValue,
|
||||
}
|
||||
container.Env = append(container.Env, e)
|
||||
result = constants.Updated
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func updateEnvVar(containers []v1.Container, envar string, shaData string) constants.Result {
|
||||
for i := range containers {
|
||||
envs := containers[i].Env
|
||||
for j := range envs {
|
||||
if envs[j].Name == envar {
|
||||
if envs[j].Value != shaData {
|
||||
envs[j].Value = shaData
|
||||
return constants.Updated
|
||||
}
|
||||
return constants.NotUpdated
|
||||
}
|
||||
}
|
||||
}
|
||||
return constants.NoEnvVarFound
|
||||
}
|
||||
413
internal/pkg/handler/upgrade_test.go
Normal file
413
internal/pkg/handler/upgrade_test.go
Normal file
@@ -0,0 +1,413 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/testutil"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
testclient "k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
var (
|
||||
client = testclient.NewSimpleClientset()
|
||||
namespace = "test-handler-" + testutil.RandSeq(5)
|
||||
configmapName = "testconfigmap-handler-" + testutil.RandSeq(5)
|
||||
secretName = "testsecret-handler-" + testutil.RandSeq(5)
|
||||
configmapWithEnvName = "testconfigmapWithEnv-handler-" + testutil.RandSeq(3)
|
||||
secretWithEnvName = "testsecretWithEnv-handler-" + testutil.RandSeq(5)
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
// Creating namespace
|
||||
testutil.CreateNamespace(namespace, client)
|
||||
|
||||
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 setup() {
|
||||
// Creating configmap
|
||||
_, err := testutil.CreateConfigMap(client, namespace, configmapName, "www.google.com")
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in configmap creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating secret
|
||||
data := "dGVzdFNlY3JldEVuY29kaW5nRm9yUmVsb2FkZXI="
|
||||
_, err = testutil.CreateSecret(client, namespace, secretName, data)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in secret creation: %v", err)
|
||||
}
|
||||
|
||||
_, err = testutil.CreateConfigMap(client, namespace, configmapWithEnvName, "www.google.com")
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in configmap creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating secret
|
||||
_, err = testutil.CreateSecret(client, namespace, secretWithEnvName, data)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in secret creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating Deployment with configmap
|
||||
_, err = testutil.CreateDeployment(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in Deployment with configmap creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating Deployment with secret
|
||||
_, err = testutil.CreateDeployment(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in Deployment with secret creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating Deployment with env var source as configmap
|
||||
_, err = testutil.CreateDeployment(client, configmapWithEnvName, namespace, false)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in Deployment with configmap configmap as env var source creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating Deployment with env var source as secret
|
||||
_, err = testutil.CreateDeployment(client, secretWithEnvName, namespace, false)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in Deployment with secret configmap as env var source creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating DaemonSet with configmap
|
||||
_, err = testutil.CreateDaemonSet(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in DaemonSet with configmap creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating DaemonSet with secret
|
||||
_, err = testutil.CreateDaemonSet(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in DaemonSet with secret creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating DaemonSet with env var source as configmap
|
||||
_, err = testutil.CreateDaemonSet(client, configmapWithEnvName, namespace, false)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in DaemonSet with configmap as env var source creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating DaemonSet with env var source as secret
|
||||
_, err = testutil.CreateDaemonSet(client, secretWithEnvName, namespace, false)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in DaemonSet with secret configmap as env var source creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating StatefulSet with configmap
|
||||
_, err = testutil.CreateStatefulSet(client, configmapName, namespace, true)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in StatefulSet with configmap creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating StatefulSet with secret
|
||||
_, err = testutil.CreateStatefulSet(client, secretName, namespace, true)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in StatefulSet with secret creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating StatefulSet with env var source as configmap
|
||||
_, err = testutil.CreateStatefulSet(client, configmapWithEnvName, namespace, false)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in StatefulSet with configmap configmap as env var source creation: %v", err)
|
||||
}
|
||||
|
||||
// Creating StatefulSet with env var source as secret
|
||||
_, err = testutil.CreateStatefulSet(client, secretWithEnvName, namespace, false)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error in StatefulSet with secret configmap as env var source creation: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func teardown() {
|
||||
// Deleting Deployment with configmap
|
||||
deploymentError := testutil.DeleteDeployment(client, namespace, configmapName)
|
||||
if deploymentError != nil {
|
||||
logrus.Errorf("Error while deleting deployment with configmap %v", deploymentError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with secret
|
||||
deploymentError = testutil.DeleteDeployment(client, namespace, secretName)
|
||||
if deploymentError != nil {
|
||||
logrus.Errorf("Error while deleting deployment with secret %v", deploymentError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with configmap as env var source
|
||||
deploymentError = testutil.DeleteDeployment(client, namespace, configmapWithEnvName)
|
||||
if deploymentError != nil {
|
||||
logrus.Errorf("Error while deleting deployment with configmap as env var source %v", deploymentError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with secret
|
||||
deploymentError = testutil.DeleteDeployment(client, namespace, secretWithEnvName)
|
||||
if deploymentError != nil {
|
||||
logrus.Errorf("Error while deleting deployment with secret as env var source %v", deploymentError)
|
||||
}
|
||||
|
||||
// Deleting DaemonSet with configmap
|
||||
daemonSetError := testutil.DeleteDaemonSet(client, namespace, configmapName)
|
||||
if daemonSetError != nil {
|
||||
logrus.Errorf("Error while deleting daemonSet with configmap %v", daemonSetError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with secret
|
||||
daemonSetError = testutil.DeleteDaemonSet(client, namespace, secretName)
|
||||
if daemonSetError != nil {
|
||||
logrus.Errorf("Error while deleting daemonSet with secret %v", daemonSetError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with configmap as env var source
|
||||
daemonSetError = testutil.DeleteDaemonSet(client, namespace, configmapWithEnvName)
|
||||
if daemonSetError != nil {
|
||||
logrus.Errorf("Error while deleting daemonSet with configmap as env var source %v", daemonSetError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with secret as env var source
|
||||
daemonSetError = testutil.DeleteDaemonSet(client, namespace, secretWithEnvName)
|
||||
if daemonSetError != nil {
|
||||
logrus.Errorf("Error while deleting daemonSet with secret as env var source %v", daemonSetError)
|
||||
}
|
||||
|
||||
// Deleting StatefulSet with configmap
|
||||
statefulSetError := testutil.DeleteStatefulSet(client, namespace, configmapName)
|
||||
if statefulSetError != nil {
|
||||
logrus.Errorf("Error while deleting statefulSet with configmap %v", statefulSetError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with secret
|
||||
statefulSetError = testutil.DeleteStatefulSet(client, namespace, secretName)
|
||||
if statefulSetError != nil {
|
||||
logrus.Errorf("Error while deleting statefulSet with secret %v", statefulSetError)
|
||||
}
|
||||
|
||||
// Deleting StatefulSet with configmap as env var source
|
||||
statefulSetError = testutil.DeleteStatefulSet(client, namespace, configmapWithEnvName)
|
||||
if statefulSetError != nil {
|
||||
logrus.Errorf("Error while deleting statefulSet with configmap as env var source %v", statefulSetError)
|
||||
}
|
||||
|
||||
// Deleting Deployment with secret as env var source
|
||||
statefulSetError = testutil.DeleteStatefulSet(client, namespace, secretWithEnvName)
|
||||
if statefulSetError != nil {
|
||||
logrus.Errorf("Error while deleting statefulSet with secret as env var source %v", statefulSetError)
|
||||
}
|
||||
|
||||
// Deleting Configmap
|
||||
err := testutil.DeleteConfigMap(client, namespace, configmapName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the configmap %v", err)
|
||||
}
|
||||
|
||||
// Deleting Secret
|
||||
err = testutil.DeleteSecret(client, namespace, secretName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the secret %v", err)
|
||||
}
|
||||
|
||||
// Deleting Configmap used as env var source
|
||||
err = testutil.DeleteConfigMap(client, namespace, configmapWithEnvName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the configmap used as env var source %v", err)
|
||||
}
|
||||
|
||||
// Deleting Secret used as env var source
|
||||
err = testutil.DeleteSecret(client, namespace, secretWithEnvName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the secret used as env var source %v", err)
|
||||
}
|
||||
|
||||
// Deleting namespace
|
||||
testutil.DeleteNamespace(namespace, client)
|
||||
|
||||
}
|
||||
|
||||
func getConfigWithAnnotations(resourceType string, name string, shaData string, annotation string) util.Config {
|
||||
return util.Config{
|
||||
Namespace: namespace,
|
||||
ResourceName: name,
|
||||
SHAValue: shaData,
|
||||
Annotation: annotation,
|
||||
Type: resourceType,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDeploymentWithConfigmap(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.stakater.com")
|
||||
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapName, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
|
||||
err := PerformRollingUpgrade(client, config, 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.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDeploymentWithConfigmapAsEnvVar(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapWithEnvName, "www.stakater.com")
|
||||
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapWithEnvName, shaData, constants.ReloaderAutoAnnotation)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
|
||||
err := PerformRollingUpgrade(client, config, deploymentFuncs)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap used as env var")
|
||||
}
|
||||
|
||||
logrus.Infof("Verifying deployment update")
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDeploymentWithSecret(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy")
|
||||
config := getConfigWithAnnotations(constants.SecretEnvVarPostfix, secretName, shaData, constants.SecretUpdateOnChangeAnnotation)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
|
||||
err := PerformRollingUpgrade(client, config, deploymentFuncs)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
}
|
||||
|
||||
logrus.Infof("Verifying deployment update")
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDeploymentWithSecretAsEnvVar(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretWithEnvName, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy")
|
||||
config := getConfigWithAnnotations(constants.SecretEnvVarPostfix, secretWithEnvName, shaData, constants.ReloaderAutoAnnotation)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
|
||||
err := PerformRollingUpgrade(client, config, deploymentFuncs)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
}
|
||||
|
||||
logrus.Infof("Verifying deployment update")
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Errorf("Deployment was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDaemonSetWithConfigmap(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.facebook.com")
|
||||
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapName, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
|
||||
err := PerformRollingUpgrade(client, config, 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.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("DaemonSet was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDaemonSetWithConfigmapAsEnvVar(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapWithEnvName, "www.facebook.com")
|
||||
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapWithEnvName, shaData, constants.ReloaderAutoAnnotation)
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
|
||||
err := PerformRollingUpgrade(client, config, daemonSetFuncs)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with configmap used as env var")
|
||||
}
|
||||
|
||||
logrus.Infof("Verifying daemonSet update")
|
||||
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("DaemonSet was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForDaemonSetWithSecret(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "d3d3LmZhY2Vib29rLmNvbQ==")
|
||||
config := getConfigWithAnnotations(constants.SecretEnvVarPostfix, secretName, shaData, constants.SecretUpdateOnChangeAnnotation)
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
|
||||
err := PerformRollingUpgrade(client, config, 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.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("DaemonSet was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForStatefulSetWithConfigmap(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapName, "www.twitter.com")
|
||||
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapName, shaData, constants.ConfigmapUpdateOnChangeAnnotation)
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
|
||||
err := PerformRollingUpgrade(client, config, 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.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("StatefulSet was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingUpgradeForStatefulSetWithSecret(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretName, "d3d3LnR3aXR0ZXIuY29t")
|
||||
config := getConfigWithAnnotations(constants.SecretEnvVarPostfix, secretName, shaData, constants.SecretUpdateOnChangeAnnotation)
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
|
||||
err := PerformRollingUpgrade(client, config, 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.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
|
||||
if !updated {
|
||||
t.Errorf("StatefulSet was not updated")
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package testutil
|
||||
import (
|
||||
"math/rand"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -40,7 +41,7 @@ func GetClient() *kubernetes.Clientset {
|
||||
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)
|
||||
logrus.Fatalf("Failed to create namespace for testing %v", err)
|
||||
} else {
|
||||
logrus.Infof("Creating namespace for testing = %s", namespace)
|
||||
}
|
||||
@@ -50,48 +51,153 @@ func CreateNamespace(namespace string, client kubernetes.Interface) {
|
||||
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)
|
||||
logrus.Fatalf("Failed to delete namespace that was created for testing %v", err)
|
||||
} else {
|
||||
logrus.Infof("Deleting namespace for testing = %s", namespace)
|
||||
}
|
||||
}
|
||||
|
||||
func getObjectMeta(namespace string, name string, autoReload bool) metav1.ObjectMeta {
|
||||
return metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: map[string]string{"firstLabel": "temp"},
|
||||
Annotations: getAnnotations(name, autoReload),
|
||||
}
|
||||
}
|
||||
|
||||
func getAnnotations(name string, autoReload bool) map[string]string {
|
||||
if autoReload {
|
||||
return map[string]string{
|
||||
constants.ReloaderAutoAnnotation: "true"}
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
constants.ConfigmapUpdateOnChangeAnnotation: name,
|
||||
constants.SecretUpdateOnChangeAnnotation: name}
|
||||
}
|
||||
|
||||
func getPodTemplateSpecWithEnvVars(name string) v1.PodTemplateSpec {
|
||||
return v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: "tutum/hello-world",
|
||||
Name: name,
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "BUCKET_NAME",
|
||||
Value: "test",
|
||||
},
|
||||
{
|
||||
Name: "CONFIGMAP_" + util.ConvertToEnvVarName(name),
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
ConfigMapKeyRef: &v1.ConfigMapKeySelector{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
Key: "test.url",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "SECRET_" + util.ConvertToEnvVarName(name),
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
SecretKeyRef: &v1.SecretKeySelector{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
Key: "test.url",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getPodTemplateSpecWithVolumes(name string) v1.PodTemplateSpec {
|
||||
return v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: "tutum/hello-world",
|
||||
Name: name,
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "BUCKET_NAME",
|
||||
Value: "test",
|
||||
},
|
||||
},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
MountPath: "etc/config",
|
||||
Name: "configmap",
|
||||
},
|
||||
{
|
||||
MountPath: "etc/sec",
|
||||
Name: "secret",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "configmap",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "secret",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Secret: &v1.SecretVolumeSource{
|
||||
SecretName: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 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{
|
||||
constants.ConfigmapUpdateOnChangeAnnotation: deploymentName,
|
||||
constants.SecretUpdateOnChangeAnnotation: deploymentName},
|
||||
},
|
||||
ObjectMeta: getObjectMeta(namespace, deploymentName, false),
|
||||
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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Template: getPodTemplateSpecWithVolumes(deploymentName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GetDeploymentWithEnvVars(namespace string, deploymentName string) *v1beta1.Deployment {
|
||||
replicaset := int32(1)
|
||||
return &v1beta1.Deployment{
|
||||
ObjectMeta: getObjectMeta(namespace, deploymentName, true),
|
||||
Spec: v1beta1.DeploymentSpec{
|
||||
Replicas: &replicaset,
|
||||
Strategy: v1beta1.DeploymentStrategy{
|
||||
Type: v1beta1.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: getPodTemplateSpecWithEnvVars(deploymentName),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -99,37 +205,24 @@ func GetDeployment(namespace string, deploymentName string) *v1beta1.Deployment
|
||||
// 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{
|
||||
constants.ConfigmapUpdateOnChangeAnnotation: daemonsetName,
|
||||
constants.SecretUpdateOnChangeAnnotation: daemonsetName},
|
||||
},
|
||||
ObjectMeta: getObjectMeta(namespace, daemonsetName, false),
|
||||
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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Template: getPodTemplateSpecWithVolumes(daemonsetName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GetDaemonSetWithEnvVars(namespace string, daemonSetName string) *v1beta1.DaemonSet {
|
||||
return &v1beta1.DaemonSet{
|
||||
ObjectMeta: getObjectMeta(namespace, daemonSetName, true),
|
||||
Spec: v1beta1.DaemonSetSpec{
|
||||
UpdateStrategy: v1beta1.DaemonSetUpdateStrategy{
|
||||
Type: v1beta1.RollingUpdateDaemonSetStrategyType,
|
||||
},
|
||||
Template: getPodTemplateSpecWithEnvVars(daemonSetName),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -137,37 +230,25 @@ func GetDaemonSet(namespace string, daemonsetName string) *v1beta1.DaemonSet {
|
||||
// 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{
|
||||
constants.ConfigmapUpdateOnChangeAnnotation: statefulsetName,
|
||||
constants.SecretUpdateOnChangeAnnotation: statefulsetName},
|
||||
},
|
||||
ObjectMeta: getObjectMeta(namespace, statefulsetName, false),
|
||||
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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Template: getPodTemplateSpecWithVolumes(statefulsetName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetStatefulSet provides statefulset for testing
|
||||
func GetStatefulSetWithEnvVar(namespace string, statefulsetName string) *v1_beta1.StatefulSet {
|
||||
return &v1_beta1.StatefulSet{
|
||||
ObjectMeta: getObjectMeta(namespace, statefulsetName, true),
|
||||
Spec: v1_beta1.StatefulSetSpec{
|
||||
UpdateStrategy: v1_beta1.StatefulSetUpdateStrategy{
|
||||
Type: v1_beta1.RollingUpdateStatefulSetStrategyType,
|
||||
},
|
||||
Template: getPodTemplateSpecWithEnvVars(statefulsetName),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -270,28 +351,46 @@ func CreateSecret(client kubernetes.Interface, namespace string, secretName stri
|
||||
}
|
||||
|
||||
// CreateDeployment creates a deployment in given namespace and returns the Deployment
|
||||
func CreateDeployment(client kubernetes.Interface, deploymentName string, namespace string) (*v1beta1.Deployment, error) {
|
||||
func CreateDeployment(client kubernetes.Interface, deploymentName string, namespace string, volumeMount bool) (*v1beta1.Deployment, error) {
|
||||
logrus.Infof("Creating Deployment")
|
||||
deploymentClient := client.ExtensionsV1beta1().Deployments(namespace)
|
||||
deployment, err := deploymentClient.Create(GetDeployment(namespace, deploymentName))
|
||||
var deploymentObj *v1beta1.Deployment
|
||||
if volumeMount {
|
||||
deploymentObj = GetDeployment(namespace, deploymentName)
|
||||
} else {
|
||||
deploymentObj = GetDeploymentWithEnvVars(namespace, deploymentName)
|
||||
}
|
||||
deployment, err := deploymentClient.Create(deploymentObj)
|
||||
time.Sleep(10 * time.Second)
|
||||
return deployment, err
|
||||
}
|
||||
|
||||
// CreateDaemonSet creates a deployment in given namespace and returns the DaemonSet
|
||||
func CreateDaemonSet(client kubernetes.Interface, daemonsetName string, namespace string) (*v1beta1.DaemonSet, error) {
|
||||
func CreateDaemonSet(client kubernetes.Interface, daemonsetName string, namespace string, volumeMount bool) (*v1beta1.DaemonSet, error) {
|
||||
logrus.Infof("Creating DaemonSet")
|
||||
daemonsetClient := client.ExtensionsV1beta1().DaemonSets(namespace)
|
||||
daemonset, err := daemonsetClient.Create(GetDaemonSet(namespace, daemonsetName))
|
||||
var daemonsetObj *v1beta1.DaemonSet
|
||||
if volumeMount {
|
||||
daemonsetObj = GetDaemonSet(namespace, daemonsetName)
|
||||
} else {
|
||||
daemonsetObj = GetDaemonSetWithEnvVars(namespace, daemonsetName)
|
||||
}
|
||||
daemonset, err := daemonsetClient.Create(daemonsetObj)
|
||||
time.Sleep(10 * time.Second)
|
||||
return daemonset, err
|
||||
}
|
||||
|
||||
// CreateStatefulSet creates a deployment in given namespace and returns the StatefulSet
|
||||
func CreateStatefulSet(client kubernetes.Interface, statefulsetName string, namespace string) (*v1_beta1.StatefulSet, error) {
|
||||
func CreateStatefulSet(client kubernetes.Interface, statefulsetName string, namespace string, volumeMount bool) (*v1_beta1.StatefulSet, error) {
|
||||
logrus.Infof("Creating StatefulSet")
|
||||
statefulsetClient := client.AppsV1beta1().StatefulSets(namespace)
|
||||
statefulset, err := statefulsetClient.Create(GetStatefulSet(namespace, statefulsetName))
|
||||
var statefulsetObj *v1_beta1.StatefulSet
|
||||
if volumeMount {
|
||||
statefulsetObj = GetStatefulSet(namespace, statefulsetName)
|
||||
} else {
|
||||
statefulsetObj = GetStatefulSetWithEnvVar(namespace, statefulsetName)
|
||||
}
|
||||
statefulset, err := statefulsetClient.Create(statefulsetObj)
|
||||
time.Sleep(10 * time.Second)
|
||||
return statefulset, err
|
||||
}
|
||||
@@ -374,28 +473,33 @@ func RandSeq(n int) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// VerifyResourceUpdate verifies whether the rolling upgrade happened or not
|
||||
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 != "" {
|
||||
reloaderEnabledValue := util.ToObjectMeta(i).Annotations[constants.ReloaderAutoAnnotation]
|
||||
reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue)
|
||||
matches := false
|
||||
if err == nil && reloaderEnabled {
|
||||
matches = true
|
||||
} else 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
|
||||
}
|
||||
if matches {
|
||||
envName := constants.EnvVarPrefix + util.ConvertToEnvVarName(config.ResourceName) + "_" + envVarPostfix
|
||||
updated := GetResourceSHA(containers, envName)
|
||||
if updated == config.SHAValue {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,37 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
//Config contains rolling upgrade configuration parameters
|
||||
type Config struct {
|
||||
Namespace string
|
||||
ResourceName string
|
||||
Annotation string
|
||||
SHAValue string
|
||||
Type string
|
||||
}
|
||||
|
||||
// GetConfigmapConfig provides utility config for configmap
|
||||
func GetConfigmapConfig(configmap *v1.ConfigMap) Config {
|
||||
return Config{
|
||||
Namespace: configmap.Namespace,
|
||||
ResourceName: configmap.Name,
|
||||
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
|
||||
SHAValue: GetSHAfromConfigmap(configmap.Data),
|
||||
Type: constants.ConfigmapEnvVarPostfix,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSecretConfig provides utility config for secret
|
||||
func GetSecretConfig(secret *v1.Secret) Config {
|
||||
return Config{
|
||||
Namespace: secret.Namespace,
|
||||
ResourceName: secret.Name,
|
||||
Annotation: constants.SecretUpdateOnChangeAnnotation,
|
||||
SHAValue: GetSHAfromSecret(secret.Data),
|
||||
Type: constants.SecretEnvVarPostfix,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -36,3 +37,14 @@ func ToObjectMeta(kubernetesObject interface{}) ObjectMeta {
|
||||
ObjectMeta: field,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseBool returns result in bool format after parsing
|
||||
func ParseBool(value interface{}) bool {
|
||||
if reflect.Bool == reflect.TypeOf(value).Kind() {
|
||||
return value.(bool)
|
||||
} else if reflect.String == reflect.TypeOf(value).Kind() {
|
||||
result, _ := strconv.ParseBool(value.(string))
|
||||
return result
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/crypto"
|
||||
)
|
||||
|
||||
// ConvertToEnvVarName converts the given text into a usable env var
|
||||
@@ -25,3 +28,21 @@ func ConvertToEnvVarName(text string) string {
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func GetSHAfromConfigmap(data map[string]string) string {
|
||||
values := []string{}
|
||||
for k, v := range data {
|
||||
values = append(values, k+"="+v)
|
||||
}
|
||||
sort.Strings(values)
|
||||
return crypto.GenerateSHA(strings.Join(values, ";"))
|
||||
}
|
||||
|
||||
func GetSHAfromSecret(data map[string][]byte) string {
|
||||
values := []string{}
|
||||
for k, v := range data {
|
||||
values = append(values, k+"="+string(v[:]))
|
||||
}
|
||||
sort.Strings(values)
|
||||
return crypto.GenerateSHA(strings.Join(values, ";"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user