Compare commits

..

20 Commits

Author SHA1 Message Date
stakater-user
67843f839a Bump Version to 0.0.13 2018-08-10 06:15:54 +00:00
Rasheed Amir
695c5b05d2 create a feature docs for seo purposes (#22)
this doc will/might help users to find this git repo and use it
2018-08-10 07:53:38 +02:00
stakater-user
4d6da476ee Bump Version to 0.0.12 2018-08-10 00:34:51 +00:00
Ahmad Iqbal Ali
d5ea5d810d add docs link in README (#21) 2018-08-10 05:13:30 +05:00
stakater-user
0d10b35d3a Bump Version to 0.0.11 2018-08-03 21:38:04 +00:00
Rasheed Amir
807e0c0c1b cleanup the readme 2018-08-03 23:16:33 +02:00
stakater-user
052bbb23e5 Bump Version to 0.0.10 2018-08-02 10:27:58 +00:00
Ahmad Iqbal Ali
28fb50598c use generic slack details (#18)
since we don't have a reloader channel at the moment.
2018-08-02 12:05:53 +02:00
stakater-user
a3e4c3a4d7 Bump Version to 0.0.9 2018-08-02 09:39:08 +00:00
Faizan Ahmad
d3bae0d3bb Optimize logging in reloader (#19)
* Optimize logging in reloader

* Fix test case failing issue

* Implement PR-19 review comments

* Place the log out of loop

* Fix change detection log
2018-08-02 11:17:35 +02:00
stakater-user
64d12a7c31 Bump Version to 0.0.8 2018-08-01 19:11:12 +00:00
Faizan Ahmad
078fc034d2 Add doc how to verify reloader working (#20)
* Add doc how to verify reloader working

* fix the text
2018-08-01 20:49:43 +02:00
stakater-user
a3125e876c Bump Version to 0.0.7 2018-08-01 10:27:17 +00:00
Faizan Ahmad
2f56d5c05b Move How it works section from readme to How it works doc (#15) 2018-08-01 11:58:39 +02:00
Faizan Ahmad
003eaee887 [STK-322] Add reloader vs k8s-trigger-controller doc (#13)
* Add reloader vs k8s-trigger-controller doc

* Fix kubectl command in readme
2018-08-01 11:41:45 +02:00
Faizan Ahmad
3030ddebf1 [STK-322] Add How it works doc (#12)
* Add How it works doc

* Update How-it-works.md

* Update how it works

* Add how it works reference in Readme
2018-08-01 11:41:26 +02:00
Faizan Ahmad
aa8b415fd4 [STK-322] Update readme to resolve any confusions (#9)
* Update readme to resolve any confusions

* Add new heading

* Remove unnecessary deployment commands from readme

* Set watch globally to true for jumbo manifest

* Update chart version to resolve conflicts

* Update readme with deploy with helm
2018-08-01 11:41:11 +02:00
stakater-user
d5c66bc235 Bump Version to 0.0.6 2018-07-31 09:57:23 +00:00
Faizan Ahmad
9bc62e1f4e Merge pull request #14 from stakater/update-namespace
Update fabric8 pipeline library version
2018-07-31 14:35:32 +05:00
faizanahmad055
1bd5fb5620 Update fabric8 pipeline library version 2018-07-31 14:34:37 +05:00
19 changed files with 258 additions and 138 deletions

View File

@@ -1 +1 @@
0.0.5 0.0.13

2
Jenkinsfile vendored
View File

@@ -1,5 +1,5 @@
#!/usr/bin/groovy #!/usr/bin/groovy
@Library('github.com/stakater/fabric8-pipeline-library@v2.5.2') @Library('github.com/stakater/fabric8-pipeline-library@v2.5.3')
def dummy def dummy

View File

@@ -2,11 +2,11 @@
## Problem ## Problem
We would like to watch if some change happens in `ConfigMap` and `Secret` objects and then perform certain upgrade on relevant `Deployment`, `Deamonset` and `Statefulset` We would like to watch if some change happens in `ConfigMap` and `Secret` objects and then perform rolling upgrade on relevant `Deployment`, `Deamonset` and `Statefulset`
## Solution ## Solution
Reloader can watch any changes in `ConfigMap` and `Secret` objects and update or recreate Pods for their associated `Deployments`, `Deamonsets` and `Statefulsets`. In this way Pods can get the latest changes in `ConfigMap` or `Secret` objects. Reloader can watch changes in `ConfigMap` and `Secret` and do rolling upgrades on Pods with their associated `Deployments`, `Deamonsets` and `Statefulsets`.
**NOTE:** This controller has been inspired from [configmapController](https://github.com/fabric8io/configmapcontroller) **NOTE:** This controller has been inspired from [configmapController](https://github.com/fabric8io/configmapcontroller)
@@ -30,51 +30,46 @@ metadata:
secret.reloader.stakater.com/reload: "foo" secret.reloader.stakater.com/reload: "foo"
``` ```
Then, providing `Reloader` is running, whenever you edit the `ConfigMap` or `Secret` called `foo` the Reloader will update the `Deployment` by adding the environment variable:
```
STAKATER_FOO_REVISION=${reloaderRevision}
```
This then triggers a rolling upgrade of your deployment's pods to use the new configuration.
Same procedure can be followed to perform rolling upgrade on `Deamonsets` and `Statefulsets` as well.
## Deploying to Kubernetes ## Deploying to Kubernetes
You can deploy Reloader by running the following kubectl commands: You can deploy Reloader by following methods:
```bash
kubectl apply -f rbac.yaml -n <namespace>
kubectl apply -f deployment.yaml -n <namespace>
```
### Vanilla Manifests ### Vanilla Manifests
You can apply vanilla manifests by running the following command You can apply vanilla manifests by running the following command
```bash ```bash
kubecl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
``` ```
By default Reloader gets deployed in `default` namespace and watches changes `secrets` and `configmaps` in all namespaces.
### Helm Charts ### Helm Charts
Or alternatively if you configured `helm` on your cluster, you can deploy Reloader via helm chart located under `deployments/kubernetes/chart/reloader` folder. Alternatively if you have configured helm on your cluster, you can add reloader to helm from our public chart repository and deploy it via helm using below mentioned commands
### Monitor All namespaces ```bash
You can monitor all namespaces in cluster by setting the `watchGlobally` flag to `true` in manifest file. helm repo add stakater https://stakater.github.io/stakater-charts
helm repo update
helm install stakater/reloader
```
## Help ## Help
**Got a question?** ### Documentation
You can find more documentation [here](docs/)
### Have a question?
File a GitHub [issue](https://github.com/stakater/Reloader/issues), or send us an [email](mailto:stakater@gmail.com). File a GitHub [issue](https://github.com/stakater/Reloader/issues), or send us an [email](mailto:stakater@gmail.com).
### Talk to us on Slack ### Talk to us on Slack
Join and talk to us on the #tools-imc channel for discussing Reloader Join and talk to us on Slack for discussing Reloader
[![Join Slack](https://stakater.github.io/README/stakater-join-slack-btn.png)](https://stakater-slack.herokuapp.com/) [![Join Slack](https://stakater.github.io/README/stakater-join-slack-btn.png)](https://stakater-slack.herokuapp.com/)
[![Chat](https://stakater.github.io/README/stakater-chat-btn.png)](https://stakater.slack.com/messages/CAN960CTG/) [![Chat](https://stakater.github.io/README/stakater-chat-btn.png)](https://stakater.slack.com/)
## Contributing ## Contributing

View File

@@ -3,7 +3,7 @@
apiVersion: v1 apiVersion: v1
name: reloader name: reloader
description: Reloader chart that runs on kubernetes description: Reloader chart that runs on kubernetes
version: 0.0.5 version: 0.0.13
keywords: keywords:
- Reloader - Reloader
- kubernetes - kubernetes

View File

@@ -7,9 +7,9 @@ reloader:
labels: labels:
provider: stakater provider: stakater
group: com.stakater.platform group: com.stakater.platform
version: 0.0.5 version: 0.0.13
image: image:
name: stakater/reloader name: stakater/reloader
tag: "0.0.5" tag: "0.0.13"
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
watchGlobally: false watchGlobally: true

View File

@@ -7,8 +7,8 @@ metadata:
app: reloader app: reloader
group: com.stakater.platform group: com.stakater.platform
provider: stakater provider: stakater
version: 0.0.5 version: 0.0.13
chart: "reloader-0.0.5" chart: "reloader-0.0.13"
release: "RELEASE-NAME" release: "RELEASE-NAME"
heritage: "Tiller" heritage: "Tiller"
name: reloader name: reloader
@@ -29,11 +29,7 @@ spec:
spec: spec:
containers: containers:
- env: - env:
- name: KUBERNETES_NAMESPACE image: "stakater/reloader:0.0.13"
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: "stakater/reloader:0.0.5"
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: reloader name: reloader
serviceAccountName: reloader serviceAccountName: reloader

View File

@@ -7,25 +7,25 @@ metadata:
app: reloader app: reloader
group: com.stakater.platform group: com.stakater.platform
provider: stakater provider: stakater
version: 0.0.5 version: 0.0.13
chart: "reloader-0.0.5" chart: "reloader-0.0.13"
release: "RELEASE-NAME" release: "RELEASE-NAME"
heritage: "Tiller" heritage: "Tiller"
name: reloader name: reloader
--- ---
apiVersion: rbac.authorization.k8s.io/v1beta1 apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role kind: ClusterRole
metadata: metadata:
labels: labels:
app: reloader app: reloader
group: com.stakater.platform group: com.stakater.platform
provider: stakater provider: stakater
version: 0.0.5 version: 0.0.13
chart: "reloader-0.0.5" chart: "reloader-0.0.13"
release: "RELEASE-NAME" release: "RELEASE-NAME"
heritage: "Tiller" heritage: "Tiller"
name: reloader-role name: reloader-role
namespace: tools namespace: default
rules: rules:
- apiGroups: - apiGroups:
- "" - ""
@@ -51,23 +51,23 @@ rules:
- patch - patch
--- ---
apiVersion: rbac.authorization.k8s.io/v1beta1 apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding kind: ClusterRoleBinding
metadata: metadata:
labels: labels:
app: reloader app: reloader
group: com.stakater.platform group: com.stakater.platform
provider: stakater provider: stakater
version: 0.0.5 version: 0.0.13
chart: "reloader-0.0.5" chart: "reloader-0.0.13"
release: "RELEASE-NAME" release: "RELEASE-NAME"
heritage: "Tiller" heritage: "Tiller"
name: reloader-role-binding name: reloader-role-binding
namespace: tools namespace: default
roleRef: roleRef:
apiGroup: rbac.authorization.k8s.io apiGroup: rbac.authorization.k8s.io
kind: Role kind: ClusterRole
name: reloader-role name: reloader-role
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: reloader name: reloader
namespace: tools namespace: default

View File

@@ -7,8 +7,8 @@ metadata:
app: reloader app: reloader
group: com.stakater.platform group: com.stakater.platform
provider: stakater provider: stakater
version: 0.0.5 version: 0.0.13
chart: "reloader-0.0.5" chart: "reloader-0.0.13"
release: "RELEASE-NAME" release: "RELEASE-NAME"
heritage: "Tiller" heritage: "Tiller"
name: reloader name: reloader
@@ -29,11 +29,7 @@ spec:
spec: spec:
containers: containers:
- env: - env:
- name: KUBERNETES_NAMESPACE image: "stakater/reloader:0.0.13"
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: "stakater/reloader:0.0.5"
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: reloader name: reloader
serviceAccountName: reloader serviceAccountName: reloader
@@ -47,25 +43,25 @@ metadata:
app: reloader app: reloader
group: com.stakater.platform group: com.stakater.platform
provider: stakater provider: stakater
version: 0.0.5 version: 0.0.13
chart: "reloader-0.0.5" chart: "reloader-0.0.13"
release: "RELEASE-NAME" release: "RELEASE-NAME"
heritage: "Tiller" heritage: "Tiller"
name: reloader name: reloader
--- ---
apiVersion: rbac.authorization.k8s.io/v1beta1 apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role kind: ClusterRole
metadata: metadata:
labels: labels:
app: reloader app: reloader
group: com.stakater.platform group: com.stakater.platform
provider: stakater provider: stakater
version: 0.0.5 version: 0.0.13
chart: "reloader-0.0.5" chart: "reloader-0.0.13"
release: "RELEASE-NAME" release: "RELEASE-NAME"
heritage: "Tiller" heritage: "Tiller"
name: reloader-role name: reloader-role
namespace: tools namespace: default
rules: rules:
- apiGroups: - apiGroups:
- "" - ""
@@ -91,23 +87,23 @@ rules:
- patch - patch
--- ---
apiVersion: rbac.authorization.k8s.io/v1beta1 apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding kind: ClusterRoleBinding
metadata: metadata:
labels: labels:
app: reloader app: reloader
group: com.stakater.platform group: com.stakater.platform
provider: stakater provider: stakater
version: 0.0.5 version: 0.0.13
chart: "reloader-0.0.5" chart: "reloader-0.0.13"
release: "RELEASE-NAME" release: "RELEASE-NAME"
heritage: "Tiller" heritage: "Tiller"
name: reloader-role-binding name: reloader-role-binding
namespace: tools namespace: default
roleRef: roleRef:
apiGroup: rbac.authorization.k8s.io apiGroup: rbac.authorization.k8s.io
kind: Role kind: ClusterRole
name: reloader-role name: reloader-role
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: reloader name: reloader
namespace: tools namespace: default

View File

@@ -12,4 +12,4 @@ reloader:
name: {{ getenv "DOCKER_IMAGE" }} name: {{ getenv "DOCKER_IMAGE" }}
tag: "{{ getenv "VERSION" }}" tag: "{{ getenv "VERSION" }}"
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
watchGlobally: false watchGlobally: true

77
docs/How-it-works.md Normal file
View File

@@ -0,0 +1,77 @@
# How it works?
Reloader watches for `ConfigMap` and `Secret` and detects if there are changes in data of these objects. After change detection reloader performs rolling upgrade on relevant Pods via associated `Deployment`, `Deamonset` and `Statefulset`.
## How change detection works
Reloader watches changes in `configmaps` and `secrets` data. As soon as it detects a change in these. It forwards these objects to an update handler which decides if and how to perform the rolling upgrade.
## Requirements for rolling upgrade
To perform rolling upgrade a `deployment`, `daemonset` or `statefulset` must have
- support for rolling upgrade strategy
- specific annotation for `configmaps` or `secrets`
The annotation value is comma separated list of `configmaps` or `secrets`. If a change is detected in data of these `configmaps` or `secrets`, reloader will perform rolling upgrades on their associated `deployments`, `daemonsets` or `statefulsets`.
### Annotation for Configmap
For a `Deployment` called `foo` have a `ConfigMap` called `foo`. Then add this annotation to your `Deployment`
```yaml
metadata:
annotations:
configmap.reloader.stakater.com/reload: "foo"
```
### Annotation for Secret
For a `Deployment` called `foo` have a `Secret` called `foo`. Then add this annotation to your `Deployment`
```yaml
metadata:
annotations:
secret.reloader.stakater.com/reload: "foo"
```
Above mentioned annotation are also work for `Daemonsets` and `Statefulsets`
## How Rolling upgrade works?
When reloader detects changes in configmap. It gets two objects of configmap. First object is an old configmap object which has a state before the latest change. Second object is new configmap object which contains latest changes. Reloader compares both objects and see whether any change in data occurred or not. If reloader finds any change in new configmap object, only then, it move forward with rolling upgrade.
After that, reloader gets the list of all deployments, daemonsets and statefulset and looks for above mentioned annotation for configmap. If the annotation value contains the configmap name, it then looks for an environment variable which can contain the configmap or secret data change hash.
### Environment variable for Configmap
If configmap name is foo then
```yaml
STAKATER_FOO_CONFIGMAP
```
### Environment variable for Secret
If Secret name is foo then
```yaml
STAKATER_FOO_SECRET
```
If the environment variable is found then it gets its value and compares it with new configmap hash value. If old value in environment variable is different from new hash value then reloader updates the environment variable. If the environment variable does not exist then it creates a new environment variable with latest hash value from configmap and updates the relevant `deployment`, `daemonset` or `statefulset`
Note: Rolling upgrade also works in the same way for secrets.
### Hash value Computation
Reloader uses SHA1 to compute hash value. SHA1 is used because it is efficient and less prone to collision.
## Monitor All Namespaces
By default reloader deploys in default namespace and monitors changes in all namespaces. To monitor changes in a specific namespace deploy the reloader in that namespace and set the `watchGlobally` flag to `false` in values file located under `deployments/kubernetes/chart/reloader`
And render manifest file using helm command
```bash
helm --namespace {replace this with namespace name} template . > reloader.yaml
```
The output file can then be used to deploy reloader in specific namespace.

View File

@@ -0,0 +1,28 @@
# Reloader vs k8s-trigger-controller
Reloader and k8s-trigger-controller are both built for same purpose. So there are quite a few similarities and differences between these.
## Similarities
- Both controllers support change detection in configmap and secrets
- Both controllers support deployment rollout
- Both controllers use SHA1 for hashing
- Both controllers have end to end as well as unit test cases.
## Differences
### Support for Daemonsets and Statefulsets.
#### k8s-trigger-controller:
k8s-trigger-controller only support for deployment rollout. It does not support daemonsets and statefulsets rollout.
#### Reloader:
Reloader supports deployment rollout as well as daemonsets and statefulsets rollout.
### Hashing usage
#### k8s-trigger-controller:
k8s-trigger-controller stores the hash value in an annotation `trigger.k8s.io/[secret|configMap]-NAME-last-hash`
#### Reloader:
Reloader stores the hash value in an environment variable `STAKATER_NAME_[SECRET|CONFIGMAP]`

View File

@@ -0,0 +1,51 @@
# Verify Reloader's Working
Reloader's working can be verified by two ways.
## Verify from logs
Check the logs of reloader and verify that you can see logs looks like below, if you are able to find these logs then it means reloader is working.
```text
Changes Detected in test-object of type 'SECRET' in namespace: test-reloader
Updated test-resource of type Deployment in namespace: test-reloader
```
Below are the details that explain these logs:
### test-object
`test-object` is the name of a `secret` or a `deployment` in which change has been detected.
### SECRET
`SECRET` is the type of `test-object`. It can either be `SECRET` or `CONFIGMAP`
### test-reloader
`test-reloader` is the name of namespace in which reloader has detected the change.
### test-resource
`test-resource` is the name of resource which is going to be updated
### Deployment
`Deployment` is the type of `test-resource`. It can either be a `Deployment`, `Daemonset` or `Statefulset`
## Verify by checking the age of Pod
A pod's age can tell whether reloader is working correctly or not. If you know that a change in a `secret` or `configmap` has occurred, then check the relevant Pod's age immediately. It should be newly created few moments ago.
### Verify from kubernetes Dashboard
`kubernetes dashboard` can be used to verify the working of Reloader. After a change in `secret` or `configmap`, check the relevant Pod's age from dashboard. It should be newly created few moments ago.
### Verify from command line
After a change in `secret` or `configmap`. Run the below mentioned command and verify that the pod is newly created.
```bash
kubectl get pods <pod name> -n <namespace name>
```

7
docs/features.md Normal file
View File

@@ -0,0 +1,7 @@
# Features
These are the key features of Reloader:
1. Restart pod in a depoloyment on change in linked/related configmap's or secret's
2. Restart pod in a daemonset on change in linked/related configmap's or secret's
3. Restart pod in a statefulset on change in linked/related configmap's or secret's

View File

@@ -2,9 +2,9 @@ package constants
const ( const (
// ConfigmapEnvVarPostfix is a postfix for configmap envVar // ConfigmapEnvVarPostfix is a postfix for configmap envVar
ConfigmapEnvVarPostfix = "_CONFIGMAP" ConfigmapEnvVarPostfix = "CONFIGMAP"
// SecretEnvVarPostfix is a postfix for secret envVar // SecretEnvVarPostfix is a postfix for secret envVar
SecretEnvVarPostfix = "_SECRET" SecretEnvVarPostfix = "SECRET"
// EnvVarPrefix is a Prefix for environment variable // EnvVarPrefix is a Prefix for environment variable
EnvVarPrefix = "STAKATER_" EnvVarPrefix = "STAKATER_"
) )

View File

@@ -25,7 +25,6 @@ var (
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
logrus.Infof("Creating namespace %s", namespace)
testutil.CreateNamespace(namespace, client) testutil.CreateNamespace(namespace, client)
logrus.Infof("Creating controller") logrus.Infof("Creating controller")
@@ -45,7 +44,6 @@ func TestMain(m *testing.M) {
logrus.Infof("Running Testcases") logrus.Infof("Running Testcases")
retCode := m.Run() retCode := m.Run()
logrus.Infof("Deleting namespace %q.\n", namespace)
testutil.DeleteNamespace(namespace, client) testutil.DeleteNamespace(namespace, client)
os.Exit(retCode) os.Exit(retCode)
@@ -268,7 +266,6 @@ func TestControllerUpdatingSecretShouldCreateEnvInDeployment(t *testing.T) {
if !updated { if !updated {
t.Errorf("Deployment was not updated") t.Errorf("Deployment was not updated")
} }
//time.Sleep(5 * time.Second)
// Deleting Deployment // Deleting Deployment
err = testutil.DeleteDeployment(client, namespace, secretName) err = testutil.DeleteDeployment(client, namespace, secretName)
@@ -330,7 +327,6 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDeployment(t *testing.T) {
if !updated { if !updated {
t.Errorf("Deployment was not updated") t.Errorf("Deployment was not updated")
} }
//time.Sleep(5 * time.Second)
// Deleting Deployment // Deleting Deployment
err = testutil.DeleteDeployment(client, namespace, secretName) err = testutil.DeleteDeployment(client, namespace, secretName)
@@ -385,7 +381,6 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDeployment(t
if updated { if updated {
t.Errorf("Deployment should not be updated by changing label in secret") t.Errorf("Deployment should not be updated by changing label in secret")
} }
//time.Sleep(5 * time.Second)
// Deleting Deployment // Deleting Deployment
err = testutil.DeleteDeployment(client, namespace, secretName) err = testutil.DeleteDeployment(client, namespace, secretName)
@@ -559,7 +554,6 @@ func TestControllerUpdatingSecretShouldCreateEnvInDaemonSet(t *testing.T) {
if !updated { if !updated {
t.Errorf("DaemonSet was not updated") t.Errorf("DaemonSet was not updated")
} }
//time.Sleep(5 * time.Second)
// Deleting DaemonSet // Deleting DaemonSet
err = testutil.DeleteDaemonSet(client, namespace, secretName) err = testutil.DeleteDaemonSet(client, namespace, secretName)
@@ -622,7 +616,6 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDaemonSet(t *testing.T) {
if !updated { if !updated {
t.Errorf("DaemonSet was not updated") t.Errorf("DaemonSet was not updated")
} }
//time.Sleep(5 * time.Second)
// Deleting DaemonSet // Deleting DaemonSet
err = testutil.DeleteDaemonSet(client, namespace, secretName) err = testutil.DeleteDaemonSet(client, namespace, secretName)
@@ -677,7 +670,6 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDaemonSet(t *
if updated { if updated {
t.Errorf("DaemonSet should not be updated by changing label in secret") t.Errorf("DaemonSet should not be updated by changing label in secret")
} }
//time.Sleep(5 * time.Second)
// Deleting DaemonSet // Deleting DaemonSet
err = testutil.DeleteDaemonSet(client, namespace, secretName) err = testutil.DeleteDaemonSet(client, namespace, secretName)
@@ -851,7 +843,6 @@ func TestControllerUpdatingSecretShouldCreateEnvInStatefulSet(t *testing.T) {
if !updated { if !updated {
t.Errorf("StatefulSet was not updated") t.Errorf("StatefulSet was not updated")
} }
//time.Sleep(5 * time.Second)
// Deleting StatefulSet // Deleting StatefulSet
err = testutil.DeleteStatefulSet(client, namespace, secretName) err = testutil.DeleteStatefulSet(client, namespace, secretName)
@@ -913,7 +904,6 @@ func TestControllerUpdatingSecretShouldUpdateEnvInStatefulSet(t *testing.T) {
if !updated { if !updated {
t.Errorf("StatefulSet was not updated") t.Errorf("StatefulSet was not updated")
} }
//time.Sleep(5 * time.Second)
// Deleting StatefulSet // Deleting StatefulSet
err = testutil.DeleteStatefulSet(client, namespace, secretName) err = testutil.DeleteStatefulSet(client, namespace, secretName)

View File

@@ -2,7 +2,6 @@ package handler
import ( import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"k8s.io/api/core/v1"
) )
// ResourceCreatedHandler contains new objects // ResourceCreatedHandler contains new objects
@@ -13,17 +12,7 @@ type ResourceCreatedHandler struct {
// Handle processes the newly created resource // Handle processes the newly created resource
func (r ResourceCreatedHandler) Handle() error { func (r ResourceCreatedHandler) Handle() error {
if r.Resource == nil { if r.Resource == nil {
logrus.Errorf("Error in Handler") logrus.Errorf("Resource creation handler received nil resource")
} else {
logrus.Infof("Detected changes in object %s", r.Resource)
// process resource based on its type
if _, ok := r.Resource.(*v1.ConfigMap); ok {
logrus.Infof("A 'configmap' has been 'Added' but no implementation found to take action")
} else if _, ok := r.Resource.(*v1.Secret); ok {
logrus.Infof("A 'secret' has been 'Added' but no implementation found to take action")
} else {
logrus.Warnf("Invalid resource: Resource should be 'Secret' or 'Configmap' but found, %v", r.Resource)
}
} }
return nil return nil
} }

View File

@@ -23,47 +23,44 @@ type ResourceUpdatedHandler struct {
// Handle processes the updated resource // Handle processes the updated resource
func (r ResourceUpdatedHandler) Handle() error { func (r ResourceUpdatedHandler) Handle() error {
if r.Resource == nil || r.OldResource == nil { if r.Resource == nil || r.OldResource == nil {
logrus.Errorf("Error in Handler") logrus.Errorf("Resource update handler received nil resource")
} else { } else {
logrus.Infof("Detected changes in object %s", r.Resource) config, envVarPostfix, oldSHAData := getConfig(r)
// process resource based on its type if config.SHAValue != oldSHAData {
rollingUpgrade(r, callbacks.RollingUpgradeFuncs{ logrus.Infof("Changes detected in %s of type '%s' in namespace: %s", config.ResourceName, envVarPostfix, config.Namespace)
ItemsFunc: callbacks.GetDeploymentItems, // process resource based on its type
ContainersFunc: callbacks.GetDeploymentContainers, rollingUpgrade(r, config, envVarPostfix, callbacks.RollingUpgradeFuncs{
UpdateFunc: callbacks.UpdateDeployment, ItemsFunc: callbacks.GetDeploymentItems,
ResourceType: "Deployment", ContainersFunc: callbacks.GetDeploymentContainers,
}) UpdateFunc: callbacks.UpdateDeployment,
rollingUpgrade(r, callbacks.RollingUpgradeFuncs{ ResourceType: "Deployment",
ItemsFunc: callbacks.GetDaemonSetItems, })
ContainersFunc: callbacks.GetDaemonSetContainers, rollingUpgrade(r, config, envVarPostfix, callbacks.RollingUpgradeFuncs{
UpdateFunc: callbacks.UpdateDaemonSet, ItemsFunc: callbacks.GetDaemonSetItems,
ResourceType: "DaemonSet", ContainersFunc: callbacks.GetDaemonSetContainers,
}) UpdateFunc: callbacks.UpdateDaemonSet,
rollingUpgrade(r, callbacks.RollingUpgradeFuncs{ ResourceType: "DaemonSet",
ItemsFunc: callbacks.GetStatefulSetItems, })
ContainersFunc: callbacks.GetStatefulsetContainers, rollingUpgrade(r, config, envVarPostfix, callbacks.RollingUpgradeFuncs{
UpdateFunc: callbacks.UpdateStatefulset, ItemsFunc: callbacks.GetStatefulSetItems,
ResourceType: "StatefulSet", ContainersFunc: callbacks.GetStatefulsetContainers,
}) UpdateFunc: callbacks.UpdateStatefulset,
ResourceType: "StatefulSet",
})
}
} }
return nil return nil
} }
func rollingUpgrade(r ResourceUpdatedHandler, upgradeFuncs callbacks.RollingUpgradeFuncs) { func rollingUpgrade(r ResourceUpdatedHandler, config util.Config, envarPostfix string, upgradeFuncs callbacks.RollingUpgradeFuncs) {
client, err := kube.GetClient() client, err := kube.GetClient()
if err != nil { if err != nil {
logrus.Fatalf("Unable to create Kubernetes client error = %v", err) logrus.Fatalf("Unable to create Kubernetes client error = %v", err)
} }
config, envVarPostfix, oldSHAData := getConfig(r) err = PerformRollingUpgrade(client, config, envarPostfix, upgradeFuncs)
if err != nil {
if config.SHAValue != oldSHAData { logrus.Errorf("Rolling upgrade for %s failed with error = %v", config.ResourceName, err)
err = PerformRollingUpgrade(client, config, envVarPostfix, upgradeFuncs)
if err != nil {
logrus.Fatalf("Rolling upgrade failed with error = %v", err)
}
} else {
logrus.Infof("Rolling upgrade will not happend because no actual change in data has been detected")
} }
} }
@@ -71,12 +68,10 @@ func getConfig(r ResourceUpdatedHandler) (util.Config, string, string) {
var oldSHAData, envVarPostfix string var oldSHAData, envVarPostfix string
var config util.Config var config util.Config
if _, ok := r.Resource.(*v1.ConfigMap); ok { if _, ok := r.Resource.(*v1.ConfigMap); ok {
logrus.Infof("Performing 'Updated' action for resource of type 'configmap'")
oldSHAData = getSHAfromConfigmap(r.OldResource.(*v1.ConfigMap).Data) oldSHAData = getSHAfromConfigmap(r.OldResource.(*v1.ConfigMap).Data)
config = getConfigmapConfig(r) config = getConfigmapConfig(r)
envVarPostfix = constants.ConfigmapEnvVarPostfix envVarPostfix = constants.ConfigmapEnvVarPostfix
} else if _, ok := r.Resource.(*v1.Secret); ok { } else if _, ok := r.Resource.(*v1.Secret); ok {
logrus.Infof("Performing 'Updated' action for resource of type 'secret'")
oldSHAData = getSHAfromSecret(r.OldResource.(*v1.Secret).Data) oldSHAData = getSHAfromSecret(r.OldResource.(*v1.Secret).Data)
config = getSecretConfig(r) config = getSecretConfig(r)
envVarPostfix = constants.SecretEnvVarPostfix envVarPostfix = constants.SecretEnvVarPostfix
@@ -112,6 +107,7 @@ func PerformRollingUpgrade(client kubernetes.Interface, config util.Config, enva
var err error var err error
for _, i := range items { for _, i := range items {
containers := upgradeFuncs.ContainersFunc(i) containers := upgradeFuncs.ContainersFunc(i)
resourceName := util.ToObjectMeta(i).Name
// find correct annotation and update the resource // find correct annotation and update the resource
annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation] annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation]
if annotationValue != "" { if annotationValue != "" {
@@ -120,13 +116,13 @@ func PerformRollingUpgrade(client kubernetes.Interface, config util.Config, enva
if value == config.ResourceName { if value == config.ResourceName {
updated := updateContainers(containers, value, config.SHAValue, envarPostfix) updated := updateContainers(containers, value, config.SHAValue, envarPostfix)
if !updated { if !updated {
logrus.Warnf("Rolling upgrade did not happen") 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 { } else {
err = upgradeFuncs.UpdateFunc(client, config.Namespace, i) err = upgradeFuncs.UpdateFunc(client, config.Namespace, i)
if err != nil { if err != nil {
logrus.Errorf("Update %s failed %v", upgradeFuncs.ResourceType, err) logrus.Errorf("Update for %s of type %s in namespace %s failed with error %v", resourceName, upgradeFuncs.ResourceType, config.Namespace, err)
} else { } else {
logrus.Infof("Updated %s of type %s", config.ResourceName, upgradeFuncs.ResourceType) logrus.Infof("Updated %s of type %s in namespace: %s ", resourceName, upgradeFuncs.ResourceType, config.Namespace)
} }
break break
} }
@@ -139,8 +135,7 @@ func PerformRollingUpgrade(client kubernetes.Interface, config util.Config, enva
func updateContainers(containers []v1.Container, annotationValue string, shaData string, envarPostfix string) bool { func updateContainers(containers []v1.Container, annotationValue string, shaData string, envarPostfix string) bool {
updated := false updated := false
envar := constants.EnvVarPrefix + util.ConvertToEnvVarName(annotationValue) + envarPostfix envar := constants.EnvVarPrefix + util.ConvertToEnvVarName(annotationValue)+ "_" + envarPostfix
logrus.Infof("Generated environment variable: %s", envar)
for i := range containers { for i := range containers {
envs := containers[i].Env envs := containers[i].Env
@@ -155,7 +150,6 @@ func updateContainers(containers []v1.Container, annotationValue string, shaData
} }
containers[i].Env = append(containers[i].Env, e) containers[i].Env = append(containers[i].Env, e)
updated = true updated = true
logrus.Infof("%s environment variable does not exist, creating a new envVar", envar)
} }
} }
return updated return updated
@@ -164,9 +158,7 @@ func updateContainers(containers []v1.Container, annotationValue string, shaData
func updateEnvVar(envs []v1.EnvVar, envar string, shaData string) bool { func updateEnvVar(envs []v1.EnvVar, envar string, shaData string) bool {
for j := range envs { for j := range envs {
if envs[j].Name == envar { if envs[j].Name == envar {
logrus.Infof("%s environment variable found", envar)
if envs[j].Value != shaData { if envs[j].Value != shaData {
logrus.Infof("Updating %s", envar)
envs[j].Value = shaData envs[j].Value = shaData
return true return true
} }

View File

@@ -22,7 +22,7 @@ var (
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
logrus.Infof("Creating namespace %s", namespace) // Creating namespace
testutil.CreateNamespace(namespace, client) testutil.CreateNamespace(namespace, client)
logrus.Infof("Setting up the test resources") logrus.Infof("Setting up the test resources")

View File

@@ -236,7 +236,6 @@ func GetResourceSHA(containers []v1.Container, envar string) string {
//ConvertResourceToSHA generates SHA from secret or configmap data //ConvertResourceToSHA generates SHA from secret or configmap data
func ConvertResourceToSHA(resourceType string, namespace string, resourceName string, data string) string { func ConvertResourceToSHA(resourceType string, namespace string, resourceName string, data string) string {
values := []string{} values := []string{}
logrus.Infof("Generating SHA for secret data")
if resourceType == SecretResourceType { if resourceType == SecretResourceType {
secret := GetSecret(namespace, resourceName, data) secret := GetSecret(namespace, resourceName, data)
for k, v := range secret.Data { for k, v := range secret.Data {
@@ -391,7 +390,7 @@ func VerifyResourceUpdate(client kubernetes.Interface, config util.Config, envVa
} }
} }
if matches { if matches {
envName := constants.EnvVarPrefix + util.ConvertToEnvVarName(annotationValue) + envVarPostfix envName := constants.EnvVarPrefix + util.ConvertToEnvVarName(annotationValue) + "_" + envVarPostfix
updated := GetResourceSHA(containers, envName) updated := GetResourceSHA(containers, envName)
if updated == config.SHAValue { if updated == config.SHAValue {