Compare commits

...

80 Commits

Author SHA1 Message Date
stakater-user
b3d3c3704a Bump Version to v0.0.34 2019-07-04 06:29:52 +00:00
Ali Kahoot
58514e8610 Merge pull request #73 from stakater/fix-dnsPolicy-issue
fix-dnsPolicy-issue
2019-07-04 11:06:41 +05:00
irti
a26f7fc4ad [fix-dnsPolicy-issue] bump package version in glide.yaml file. k8s.io/api version 1.8.0 to 1.10.0 and client go version 5.0.0 to 6.0.0 2019-07-04 10:12:55 +05:00
stakater-user
8b824ef26a Bump Version to v0.0.33 2019-07-01 12:09:23 +00:00
Irtiza Ali
5fd170a7ca Merge pull request #69 from chrisns/kustomize
add Kustomize deployment code docs
2019-07-01 16:44:50 +05:00
Chris Nesbitt-Smith
69487f6caf update readme for kustomize 2019-06-27 14:34:07 +01:00
Chris Nesbitt-Smith
401a94bd36 add kustomization.yaml 2019-06-27 10:59:02 +01:00
stakater-user
bf12cbec15 Bump Version to v0.0.32 2019-06-27 08:30:31 +00:00
Irtiza Ali
fdc223a4a6 Merge pull request #68 from DevotedHealth/affinity_tolerations
Permit passing resources, tolerations, affinity to Helm chart
2019-06-27 13:07:34 +05:00
Steve Huff
dcbc0e0de0 Permit passing resources, tolerations, affinity to Helm chart
These values are all empty by default.
2019-06-26 18:44:39 +00:00
stakater-user
aff377718c Bump Version to v0.0.31 2019-06-25 09:27:27 +00:00
Ali Kahoot
112e8ba89d Merge pull request #67 from stakater/add-node-selector-support
add-node-selector-support
2019-06-25 14:04:40 +05:00
irti
c2e6231a46 [add-node-selector-support] revert README.md doc change 2019-06-20 12:21:35 +05:00
irti
51b42dc098 [add-node-selector-support] add char in README.md 2019-06-20 12:18:31 +05:00
irti
43200e127a [add-node-selector-support] add nodeSelector param in values.yaml file 2019-06-20 12:03:37 +05:00
irti
6db5106f85 [add-node-selector-support] fix issue 2019-06-20 11:55:21 +05:00
irti
703c0ea56e [add-node-selector-support] add nodeSelector support 2019-06-20 11:36:12 +05:00
stakater-user
21563abc07 Bump Version to v0.0.30 2019-06-11 07:36:19 +00:00
Ali Kahoot
ce96eb3810 Merge pull request #65 from blurpy/filesys_and_role
Fix issue with readOnlyRootFilesystem and statefulsets permissions
2019-06-11 12:13:13 +05:00
Christian Ihle
b5c8ee2ab9 Add optional support for readOnlyRootFilesystem 2019-06-06 11:59:42 +02:00
Christian Ihle
c27bb3929b Split permissions for apps and extensions apigroups since statefulsets does not have extensions 2019-06-06 11:54:14 +02:00
stakater-user
67913c9985 Bump Version to v0.0.29 2019-05-23 10:04:32 +00:00
Ali Kahoot
9dac1a30b6 Merge pull request #64 from cko/alpine_update
Update alpine container base image to 3.9
2019-05-23 14:41:30 +05:00
Christine Koppelt
ac7f9d09cc update alpine container base image to 3.9 2019-05-23 10:55:06 +02:00
stakater-user
d8ae3c76da Bump Version to v0.0.28 2019-05-08 10:22:39 +00:00
Ali Kahoot
3f115618cc Merge pull request #62 from stakater/issue-61
Initial implementation of fix for issue 61
2019-05-08 14:59:43 +05:00
faizanahmad055
06aa382910 Initial implementation of fix for issue 61
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-05-07 10:51:58 +02:00
stakater-user
3b69599c77 Bump Version to v0.0.27 2019-04-25 10:18:02 +00:00
Ali Kahoot
125e7536af Merge pull request #60 from stakater/fix-config-change-logs-issue
fix-config-change-logs-issue
2019-04-25 14:55:07 +05:00
irti
66f9b07817 [fix-config-change-logs-issue] fixed log statement placement 2019-04-25 14:19:52 +05:00
irti
40aa9955cd [fix-config-change-logs-issue] fixed the issue in create.go file 2019-04-25 14:16:42 +05:00
irti
bfff7104aa [fix-config-change-logs-issue] logs issue fixed 2019-04-25 14:11:31 +05:00
Ali Kahoot
c0acfd0503 Merge pull request #58 from stakater/sealed-secret-doc
Sealed secret doc
2019-03-18 20:18:11 +05:00
faizanahmad055
379b6c0131 Add doc for how to use sealed secrets with reloader
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-03-18 16:14:47 +01:00
faizanahmad055
3bf427e985 Add doc for how to use sealed secrets with reloader
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-03-18 16:13:55 +01:00
stakater-user
2b6e5455dc Bump Version to v0.0.26 2019-02-20 10:57:07 +00:00
Ali Kahoot
9bc8d6b67d Merge pull request #56 from stakater/add-initContainer-support
Initial implementation for init container support
2019-02-20 15:32:44 +05:00
faizanahmad055
0c340fcb48 Fix same name configmap and secret conflict
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-02-18 12:09:53 +01:00
faizanahmad055
889b16718a Add test cases
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-02-18 10:20:52 +01:00
faizanahmad055
512cbd8c85 Fix incorrect container update
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-02-16 16:52:12 +01:00
faizanahmad055
39944497f3 Implement golang-ci comment
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-02-16 15:50:47 +01:00
faizanahmad055
6fb1266637 Initial implementation for init container support
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-02-16 15:43:56 +01:00
stakater-user
724cda887e Bump Version to v0.0.25 2019-02-12 08:28:39 +00:00
Muhammad Ahsan
d29f3716b2 Merge pull request #53 from stakater/fix-helper-func
append reloader- to serviceAccountName
2019-02-12 13:03:43 +05:00
kahootali
2131f0ebf3 append reloader- to serviceAccountName 2019-02-12 12:20:28 +05:00
stakater-user
0f052162a2 Bump Version to v0.0.24 2019-02-08 10:55:07 +00:00
Faizan Ahmad
02c6de97c8 Merge pull request #50 from ParticleDecay/feat/annotation-flag
Parameterize all annotations
2019-02-08 11:31:38 +01:00
kahootali
16bce16f81 add custom annotation 2019-02-08 15:05:18 +05:00
Joey Espinosa
33443ccb29 feat: add cli flags to helm chart 2019-02-06 12:46:17 -05:00
Joey Espinosa
75b00733bf feat: parameterize all annotations 2019-02-04 12:33:53 -05:00
stakater-user
d2335f8ffd Bump Version to v0.0.23 2019-02-01 12:21:59 +00:00
Ali Kahoot
87f3a32f68 Merge pull request #49 from stakater/fix-48
Add support for envFrom for autoUpdate
2019-02-01 16:57:46 +05:00
faizanahmad055
95bd5e497f Use single container loop for envs
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-02-01 12:06:18 +01:00
faizanahmad055
333957d82a Implemented golang CI comment
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-01-31 16:32:47 +01:00
faizanahmad055
75f67ffa6e Add support for envFrom for autoUpdate
Signed-off-by: faizanahmad055 <faizanahmad@217-212-164-26.customer.telia.com>
2019-01-31 16:03:53 +01:00
Ziming Miao
0558fc3723 fix typo (#47) 2019-01-30 10:38:23 +05:00
stakater-user
b637e33d9d Bump Version to v0.0.22 2019-01-25 13:24:41 +00:00
Faizan Ahmad
130741480e 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>
2019-01-25 14:00:21 +01:00
stakater-user
cd19d739ab Bump Version to v0.0.21 2019-01-21 08:54:49 +00:00
Ali Kahoot
f15ec9b4d4 Merge pull request #44 from stakater/update-jenkins-file
updates pipeline library version
2019-01-21 13:34:39 +05:00
ahsan-storm
013fcdc052 updates pipeline library version 2019-01-21 13:10:31 +05:00
stakater-user
78e98c7999 Bump Version to 0.0.20 2019-01-15 07:34:03 +00:00
Ali Kahoot
44c6333910 Merge pull request #42 from stakater/update-jenkins-file
updates jenkins file
2019-01-15 12:14:33 +05:00
ahsan-storm
0316bcd938 updates jenkins file with latest changes 2019-01-15 12:13:42 +05:00
stakater-user
8c77c230e0 Bump Version to 0.0.19 2019-01-15 07:06:57 +00:00
Ali Kahoot
bcffb62e3f Merge pull request #41 from stakater/update-start-controller-log
Update start controller log
2019-01-15 11:46:29 +05:00
ahsan-storm
85c10da63d updates jenkins file 2019-01-10 19:56:18 +05:00
faizanahmad055
b17ab76a24 Update start controller log
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2019-01-10 18:34:23 +05:00
Faizan Ahmad
23ab5692fa Update chart for public helm repo (#36)
* Update chart according to practices of helm public repo

Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>

* Add new line at the end of files

Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2018-12-10 23:50:54 +01:00
Ali Kahoot
55c93a4dd8 Merge pull request #35 from stakater/update-readme-annotation-location
Update readme to explain annotation position
2018-12-05 16:06:14 +05:00
faizanahmad055
32eb9e7959 Update readme to explain annotation position
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2018-12-05 15:43:18 +05:00
Ahmad Iqbal Ali
09046c45ff Set Reloader specific slack channel url 2018-12-05 15:32:36 +05:00
Faizan Ahmad
f346ca84ab Update readme and docs (#34)
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2018-12-04 21:33:20 +01:00
stakater-user
5041d1a1cf Bump Version to 0.0.18 2018-10-11 11:55:45 +00:00
Faizan Ahmad
1ad93145b4 Merge pull request #31 from stakater/fix-annotation-placement-confusion
Fix annotation placement confusion in readme
2018-10-11 16:33:27 +05:00
faizanahmad055
61b398539e Fix annotation placement confusion in readme
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2018-10-11 15:38:26 +05:00
stakater-user
0cb86cf665 Bump Version to 0.0.17 2018-10-08 11:24:46 +00:00
Ali Kahoot
b973c37a4f Merge pull request #30 from stakater/issue-29
Update readme about how to define multiple configmaps and secrets
2018-10-08 16:02:55 +05:00
faizanahmad055
1cfa756178 Remove spaces from comma seperated list in readme
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2018-10-08 14:08:13 +05:00
faizanahmad055
e8854000cb Update readme about how to define multiple configmaps and secrets
Signed-off-by: faizanahmad055 <faizan.ahmad55@outlook.com>
2018-10-08 12:22:04 +05:00
49 changed files with 2446 additions and 986 deletions

View File

@@ -1 +1 @@
0.0.16
v0.0.34

8
Jenkinsfile vendored
View File

@@ -1,8 +1,10 @@
#!/usr/bin/groovy
@Library('github.com/stakater/fabric8-pipeline-library@v2.7.2')
@Library('github.com/stakater/fabric8-pipeline-library@v2.10.8')
def dummy
goBuildAndRelease {
}
chartRepositoryURL = 'https://chartmuseum.release.stakater.com'
publicChartRepositoryURL = 'https://stakater.github.io/stakater-charts'
publicChartGitURL = 'git@github.com:stakater/stakater-charts.git'
}

107
README.md
View File

@@ -13,32 +13,95 @@
## Problem
We would like to watch if some change happens in `ConfigMap` and/or `Secret`; then perform a rolling upgrade on relevant `Deployment`, `Deamonset` and `Statefulset`
We would like to watch if some change happens in `ConfigMap` and/or `Secret`; then perform a rolling upgrade on relevant `Deployment`, `Daemonset` and `Statefulset`
## Solution
Reloader can watch changes in `ConfigMap` and `Secret` and do rolling upgrades on Pods with their associated `Deployments`, `Deamonsets` and `Statefulsets`.
Reloader can watch changes in `ConfigMap` and `Secret` and do rolling upgrades on Pods with their associated `Deployments`, `Daemonsets` and `Statefulsets`.
## How to use Reloader
For a `Deployment` called `foo` have a `ConfigMap` called `foo-configmap`. Then add this annotation to your `Deployment`
For a `Deployment` called `foo` have a `ConfigMap` called `foo-configmap` or `Secret` called `foo-secret` or both. Then add your annotation (by default `reloader.stakater.com/auto`) 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 the auto annotation to `"false"` (`reloader.stakater.com/auto: "false"`) or remove it altogether, 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
kind: Deployment
metadata:
annotations:
configmap.reloader.stakater.com/reload: "foo-configmap"
spec:
template:
metadata:
```
OR
For a `Deployment` called `foo` have a `Secret` called `foo-secret`. Then add this annotation to your `Deployment`
Use comma separated list to define multiple configmaps.
```yaml
kind: Deployment
metadata:
annotations:
configmap.reloader.stakater.com/reload: "foo-configmap,bar-configmap,baz-configmap"
spec:
template:
metadata:
```
### 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
kind: Deployment
metadata:
annotations:
secret.reloader.stakater.com/reload: "foo-secret"
spec:
template:
metadata:
```
Use comma separated list to define multiple secrets.
```yaml
kind: Deployment
metadata:
annotations:
secret.reloader.stakater.com/reload: "foo-secret,bar-secret,baz-secret"
spec:
template:
metadata:
```
### NOTES
- Reloader also supports [sealed-secrets](https://github.com/bitnami-labs/sealed-secrets). [Here](docs/Reloader-with-Sealed-Secrets.md) are the steps to use sealed-secrets with reloader.
- `reloader.stakater.com/auto: "true"` will only reload the pod, if the configmap or secret is used (as a volume mount or as an env) in `Deployment/Daemonsets/Statefulsets`
- `secret.reloader.stakater.com/reload` or `configmap.reloader.stakater.com/reload` annotation will reload the pod upon changes in specified configmap or secret, irrespective of the usage of configmap or secret.
- you may override the auto annotation with the `--auto-annotation` flag
- you may override the configmap annotation with the `--configmap-annotation` flag
- you may override the secret annotation with the `--secret-annotation` flag
## Deploying to Kubernetes
You can deploy Reloader by following methods:
@@ -53,6 +116,30 @@ kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/depl
By default Reloader gets deployed in `default` namespace and watches changes `secrets` and `configmaps` in all namespaces.
### Vanilla kustomize
You can also apply the vanilla manifests by running the following command
```bash
kubectl apply -k https://github.com/stakater/Reloader/deployments/kubernetes
```
Similarly to vanilla manifests get deployed in `default` namespace and watches changes `secrets` and `configmaps` in all namespaces.
### Kustomize
You can write your own `kustomization.yaml` using ours as a 'base' and write patches to tweak the configuration.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: reloader-
bases:
- https://github.com/stakater/Reloader/deployments/kubernetes
namespace: reloader
```
### Helm Charts
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
@@ -65,6 +152,12 @@ helm repo update
helm install stakater/reloader
```
**Note:** By default reloader watches in all namespaces. To watch in single namespace, please run following command. It will install reloader in `test` namespace which will only watch `Deployments`, `Daemonsets` and `Statefulsets` in `test` namespace.
```bash
helm install stakater/reloader --set reloader.watchGlobally=false --namespace test
```
## Help
### Documentation
@@ -78,7 +171,7 @@ File a GitHub [issue](https://github.com/stakater/Reloader/issues), or send us a
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/)
[![Chat](https://stakater.github.io/README/stakater-chat-btn.png)](https://stakater.slack.com/)
[![Chat](https://stakater.github.io/README/stakater-chat-btn.png)](https://stakater.slack.com/messages/CC5S05S12)
## Contributing

View File

@@ -1,4 +1,4 @@
FROM alpine:3.4
FROM alpine:3.9
MAINTAINER "Stakater Team"
RUN apk add --update ca-certificates

View File

@@ -0,0 +1,2 @@
# OWNERS file for Kubernetes
OWNERS

View File

@@ -3,11 +3,27 @@
apiVersion: v1
name: reloader
description: Reloader chart that runs on kubernetes
version: 0.0.16
version: v0.0.34
appVersion: v0.0.34
keywords:
- Reloader
- kubernetes
home: https://github.com/stakater/Reloader
sources:
- https://github.com/stakater/IngressMonitorController
icon: https://raw.githubusercontent.com/stakater/Reloader/master/assets/web/reloader-round-100px.png
maintainers:
- name: Stakater
email: hello@stakater.com
email: hello@stakater.com
- name: rasheedamir
email: rasheed@aurorasolutions.io
- name: waseem-h
email: waseemhassan@stakater.com
- name: faizanahmad055
email: faizan.ahmad55@outlook.com
- name: kahootali
email: ali.kahoot@aurorasolutions.io
- name: ahmadiq
email: ahmad@aurorasolutions.io
- name: ahsan-storm
email: ahsanmuhammad1@outlook.com

View File

@@ -0,0 +1,14 @@
approvers:
- faizanahmad055
- kahootali
- ahmadiq
- waseem-h
- rasheedamir
- ahsan-storm
reviewers:
- faizanahmad055
- kahootali
- ahmadiq
- waseem-h
- rasheedamir
- ahsan-storm

View File

@@ -0,0 +1,7 @@
- For a `Deployment` called `foo` have a `ConfigMap` called `foo-configmap`. Then add this annotation to main metadata of your `Deployment`
configmap.reloader.stakater.com/reload: "foo-configmap"
- For a `Deployment` called `foo` have a `Secret` called `foo-secret`. Then add this annotation to main metadata of your `Deployment`
secret.reloader.stakater.com/reload: "foo-secret"
- After successful installation, your pods will get rolling updates when a change in data of configmap or secret will happen.

View File

@@ -15,19 +15,20 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "reloader-labels.selector" -}}
app: {{ template "reloader-name" . }}
group: {{ .Values.reloader.labels.group }}
provider: {{ .Values.reloader.labels.provider }}
{{- end -}}
{{- define "reloader-labels.stakater" -}}
{{ template "reloader-labels.selector" . }}
version: {{ .Values.reloader.labels.version }}
{{- end -}}
{{- define "reloader-labels.chart" -}}
app: {{ template "reloader-name" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: {{ .Release.Name | quote }}
heritage: {{ .Release.Service | quote }}
{{- end -}}
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
{{- define "reloader-serviceAccountName" -}}
{{- if .Values.reloader.serviceAccount.create -}}
{{ default (include "reloader-fullname" .) .Values.reloader.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.reloader.serviceAccount.name }}
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,46 @@
{{- if and .Values.reloader.watchGlobally (.Values.reloader.rbac.enabled) }}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
{{ include "reloader-labels.chart" . | indent 4 }}
{{- if .Values.reloader.rbac.labels }}
{{ toYaml .Values.reloader.rbac.labels | indent 4 }}
{{- end }}
{{- if .Values.reloader.matchLabels }}
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
{{- end }}
name: {{ template "reloader-name" . }}-role
namespace: {{ .Release.Namespace }}
rules:
- apiGroups:
- ""
resources:
- secrets
- configmaps
verbs:
- list
- get
- watch
- apiGroups:
- "apps"
resources:
- deployments
- daemonsets
- statefulsets
verbs:
- list
- get
- update
- patch
- apiGroups:
- "extensions"
resources:
- deployments
- daemonsets
verbs:
- list
- get
- update
- patch
{{- end }}

View File

@@ -0,0 +1,23 @@
{{- if and .Values.reloader.watchGlobally (.Values.reloader.rbac.enabled) }}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
labels:
{{ include "reloader-labels.chart" . | indent 4 }}
{{- if .Values.reloader.rbac.labels }}
{{ toYaml .Values.reloader.rbac.labels | indent 4 }}
{{- end }}
{{- if .Values.reloader.matchLabels }}
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
{{- end }}
name: {{ template "reloader-name" . }}-role-binding
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ template "reloader-name" . }}-role
subjects:
- kind: ServiceAccount
name: {{ template "reloader-serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}

View File

@@ -1,31 +1,114 @@
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
{{- if .Values.reloader.deployment.annotations }}
annotations:
{{ toYaml .Values.reloader.deployment.annotations | indent 4 }}
{{- end }}
labels:
{{ include "reloader-labels.stakater" . | indent 4 }}
{{ include "reloader-labels.chart" . | indent 4 }}
{{- if .Values.reloader.deployment.labels }}
{{ toYaml .Values.reloader.deployment.labels | indent 4 }}
{{- end }}
{{- if .Values.reloader.matchLabels }}
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
{{- end }}
name: {{ template "reloader-name" . }}
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
{{ include "reloader-labels.selector" . | indent 6 }}
app: {{ template "reloader-name" . }}
release: {{ .Release.Name | quote }}
{{- if .Values.reloader.matchLabels }}
{{ toYaml .Values.reloader.matchLabels | indent 6 }}
{{- end }}
template:
metadata:
labels:
{{ include "reloader-labels.selector" . | indent 8 }}
{{ include "reloader-labels.chart" . | indent 8 }}
{{- if .Values.reloader.deployment.labels }}
{{ toYaml .Values.reloader.deployment.labels | indent 8 }}
{{- end }}
{{- if .Values.reloader.matchLabels }}
{{ toYaml .Values.reloader.matchLabels | indent 8 }}
{{- end }}
spec:
{{- if .Values.reloader.deployment.nodeSelector }}
nodeSelector:
{{ toYaml .Values.reloader.deployment.nodeSelector | indent 8 }}
{{- end }}
{{- if .Values.reloader.deployment.affinity }}
affinity:
{{ toYaml .Values.reloader.deployment.affinity | indent 8 }}
{{- end }}
{{- if .Values.reloader.deployment.tolerations }}
tolerations:
{{ toYaml .Values.reloader.deployment.tolerations | indent 8 }}
{{- end }}
containers:
- env:
{{- range $name, $value := .Values.reloader.deployment.env.open }}
{{- if not (empty $value) }}
- name: {{ $name | quote }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
{{- $secret_name := include "reloader-fullname" . }}
{{- range $name, $value := .Values.reloader.deployment.env.secret }}
{{- if not ( empty $value) }}
- name: {{ $name | quote }}
valueFrom:
secretKeyRef:
name: {{ $secret_name }}
key: {{ $name | quote }}
{{- end }}
{{- end }}
{{- range $name, $value := .Values.reloader.deployment.env.field }}
{{- if not ( empty $value) }}
- name: {{ $name | quote }}
valueFrom:
fieldRef:
fieldPath: {{ $value | quote}}
{{- end }}
{{- end }}
{{- if eq .Values.reloader.watchGlobally false }}
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
{{- end }}
image: "{{ .Values.reloader.image.name }}:{{ .Values.reloader.image.tag }}"
imagePullPolicy: {{ .Values.reloader.image.pullPolicy }}
image: "{{ .Values.reloader.deployment.image.name }}:{{ .Values.reloader.deployment.image.tag }}"
imagePullPolicy: {{ .Values.reloader.deployment.image.pullPolicy }}
name: {{ template "reloader-name" . }}
serviceAccountName: {{ template "reloader-name" . }}
{{- if eq .Values.reloader.readOnlyRootFileSystem true }}
volumeMounts:
- mountPath: /tmp/
name: tmp-volume
{{- end }}
{{- if .Values.reloader.custom_annotations }}
args:
{{- if .Values.reloader.custom_annotations.configmap }}
- "--configmap-annotation"
- "{{ .Values.reloader.custom_annotations.configmap }}"
{{- end }}
{{- if .Values.reloader.custom_annotations.secret }}
- "--secret-annotation"
- "{{ .Values.reloader.custom_annotations.secret }}"
{{- end }}
{{- if .Values.reloader.custom_annotations.auto }}
- "--auto-annotation"
- "{{ .Values.reloader.custom_annotations.auto }}"
{{- end }}
{{- end }}
{{- if .Values.reloader.deployment.resources }}
resources:
{{ toYaml .Values.reloader.deployment.resources | indent 10 }}
{{- end }}
serviceAccountName: {{ template "reloader-serviceAccountName" . }}
{{- if eq .Values.reloader.readOnlyRootFileSystem true }}
volumes:
- emptyDir: {}
name: tmp-volume
{{- end }}

View File

@@ -1,107 +0,0 @@
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
{{ include "reloader-labels.stakater" . | indent 4 }}
{{ include "reloader-labels.chart" . | indent 4 }}
name: {{ template "reloader-name" . }}
---
{{- if .Values.reloader.watchGlobally }}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
{{ include "reloader-labels.stakater" . | indent 4 }}
{{ include "reloader-labels.chart" . | indent 4 }}
name: {{ template "reloader-name" . }}-role
namespace: {{ .Release.Namespace }}
rules:
- apiGroups:
- ""
resources:
- secrets
- configmaps
verbs:
- list
- get
- watch
- apiGroups:
- ""
- "extensions"
- "apps"
resources:
- deployments
- daemonsets
- statefulsets
verbs:
- list
- get
- update
- patch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
labels:
{{ include "reloader-labels.stakater" . | indent 4 }}
{{ include "reloader-labels.chart" . | indent 4 }}
name: {{ template "reloader-name" . }}-role-binding
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ template "reloader-name" . }}-role
subjects:
- kind: ServiceAccount
name: {{ template "reloader-name" . }}
namespace: {{ .Release.Namespace }}
{{- else }}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
labels:
{{ include "reloader-labels.stakater" . | indent 4 }}
{{ include "reloader-labels.chart" . | indent 4 }}
name: {{ template "reloader-name" . }}-role
namespace: {{ .Release.Namespace }}
rules:
- apiGroups:
- ""
resources:
- secrets
- configmaps
verbs:
- list
- get
- watch
- apiGroups:
- ""
- "extensions"
- "apps"
resources:
- deployments
- daemonsets
- statefulsets
verbs:
- list
- get
- update
- patch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
labels:
{{ include "reloader-labels.stakater" . | indent 4 }}
{{ include "reloader-labels.chart" . | indent 4 }}
name: {{ template "reloader-name" . }}-role-binding
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ template "reloader-name" . }}-role
subjects:
- kind: ServiceAccount
name: {{ template "reloader-name" . }}
namespace: {{ .Release.Namespace }}
{{- end }}

View File

@@ -0,0 +1,46 @@
{{- if and (not (.Values.reloader.watchGlobally)) (.Values.reloader.rbac.enabled) }}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
labels:
{{ include "reloader-labels.chart" . | indent 4 }}
{{- if .Values.reloader.rbac.labels }}
{{ toYaml .Values.reloader.rbac.labels | indent 4 }}
{{- end }}
{{- if .Values.reloader.matchLabels }}
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
{{- end }}
name: {{ template "reloader-name" . }}-role
namespace: {{ .Release.Namespace }}
rules:
- apiGroups:
- ""
resources:
- secrets
- configmaps
verbs:
- list
- get
- watch
- apiGroups:
- "apps"
resources:
- deployments
- daemonsets
- statefulsets
verbs:
- list
- get
- update
- patch
- apiGroups:
- "extensions"
resources:
- deployments
- daemonsets
verbs:
- list
- get
- update
- patch
{{- end }}

View File

@@ -0,0 +1,23 @@
{{- if and (not (.Values.reloader.watchGlobally)) (.Values.reloader.rbac.enabled) }}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
labels:
{{ include "reloader-labels.chart" . | indent 4 }}
{{- if .Values.reloader.rbac.labels }}
{{ toYaml .Values.reloader.rbac.labels | indent 4 }}
{{- end }}
{{- if .Values.reloader.matchLabels }}
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
{{- end }}
name: {{ template "reloader-name" . }}-role-binding
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ template "reloader-name" . }}-role
subjects:
- kind: ServiceAccount
name: {{ template "reloader-serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}

View File

@@ -0,0 +1,14 @@
{{- if .Values.reloader.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
{{ include "reloader-labels.chart" . | indent 4 }}
{{- if .Values.reloader.serviceAccount.labels }}
{{ toYaml .Values.reloader.serviceAccount.labels | indent 4 }}
{{- end }}
{{- if .Values.reloader.matchLabels }}
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
{{- end }}
name: {{ template "reloader-serviceAccountName" . }}
{{- end }}

View File

@@ -4,12 +4,76 @@ kubernetes:
host: https://kubernetes.default
reloader:
labels:
provider: stakater
group: com.stakater.platform
version: 0.0.16
image:
name: stakater/reloader
tag: "0.0.16"
pullPolicy: IfNotPresent
watchGlobally: true
watchGlobally: true
# Set to true if you have a pod security policy that enforces readOnlyRootFilesystem
readOnlyRootFileSystem: false
matchLabels: {}
deployment:
nodeSelector:
# cloud.google.com/gke-nodepool: default-pool
# An affinity stanza to be applied to the Deployment.
# Example:
# affinity:
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
# - matchExpressions:
# - key: "node-role.kubernetes.io/infra-worker"
# operator: "Exists"
affinity: {}
# A list of tolerations to be applied to the Deployment.
# Example:
# tolerations:
# - key: "node-role.kubernetes.io/infra-worker"
# operator: "Exists"
# effect: "NoSchedule"
tolerations: []
annotations: {}
labels:
provider: stakater
group: com.stakater.platform
version: v0.0.34
image:
name: stakater/reloader
tag: "v0.0.34"
pullPolicy: IfNotPresent
# Support for extra environment variables.
env:
# Open supports Key value pair as environment variables.
open:
# secret supports Key value pair as environment variables. It gets the values based on keys from default reloader secret if any.
secret:
# field supports Key value pair as environment variables. It gets the values from other fields of pod.
field:
# Specify resource requests/limits for the deployment.
# Example:
# resources:
# limits:
# cpu: "100m"
# memory: "512Mi"
# requests:
# cpu: "10m"
# memory: "128Mi"
resources: {}
rbac:
enabled: true
labels: {}
# Service account config for the agent pods
serviceAccount:
# Specifies whether a ServiceAccount should be created
create: true
labels: {}
# The name of the ServiceAccount to use.
# If not set and create is true, a name is generated using the fullname template
name: reloader
# Optional flags to pass to the Reloader entrypoint
# Example:
# custom_annotations:
# configmap: "my.company.com/configmap"
# secret: "my.company.com/secret"
custom_annotations: {}

View File

@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- manifests/clusterrole.yaml
- manifests/clusterrolebinding.yaml
- manifests/role.yaml
- manifests/rolebinding.yaml
- manifests/serviceaccount.yaml
- manifests/deployment.yaml

View File

@@ -0,0 +1,45 @@
---
# Source: reloader/templates/clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
app: reloader
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader-role
namespace: default
rules:
- apiGroups:
- ""
resources:
- secrets
- configmaps
verbs:
- list
- get
- watch
- apiGroups:
- "apps"
resources:
- deployments
- daemonsets
- statefulsets
verbs:
- list
- get
- update
- patch
- apiGroups:
- "extensions"
resources:
- deployments
- daemonsets
verbs:
- list
- get
- update
- patch

View File

@@ -0,0 +1,22 @@
---
# Source: reloader/templates/clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
labels:
app: reloader
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader-role-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: reloader-role
subjects:
- kind: ServiceAccount
name: reloader
namespace: default

View File

@@ -1,16 +1,17 @@
---
# Source: reloader/templates/deployment.yaml
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: reloader
group: com.stakater.platform
provider: stakater
version: 0.0.16
chart: "reloader-0.0.16"
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
group: com.stakater.platform
provider: stakater
version: v0.0.34
name: reloader
spec:
replicas: 1
@@ -18,19 +19,23 @@ spec:
selector:
matchLabels:
app: reloader
group: com.stakater.platform
provider: stakater
release: "RELEASE-NAME"
template:
metadata:
labels:
app: reloader
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
group: com.stakater.platform
provider: stakater
version: v0.0.34
spec:
containers:
- env:
image: "stakater/reloader:0.0.16"
image: "stakater/reloader:v0.0.34"
imagePullPolicy: IfNotPresent
name: reloader
serviceAccountName: reloader

View File

@@ -1,73 +0,0 @@
---
# Source: reloader/templates/rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: reloader
group: com.stakater.platform
provider: stakater
version: 0.0.16
chart: "reloader-0.0.16"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
app: reloader
group: com.stakater.platform
provider: stakater
version: 0.0.16
chart: "reloader-0.0.16"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader-role
namespace: default
rules:
- apiGroups:
- ""
resources:
- secrets
- configmaps
verbs:
- list
- get
- watch
- apiGroups:
- ""
- "extensions"
- "apps"
resources:
- deployments
- daemonsets
- statefulsets
verbs:
- list
- get
- update
- patch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
labels:
app: reloader
group: com.stakater.platform
provider: stakater
version: 0.0.16
chart: "reloader-0.0.16"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader-role-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: reloader-role
subjects:
- kind: ServiceAccount
name: reloader
namespace: default

View File

@@ -0,0 +1,4 @@
---
# Source: reloader/templates/role.yaml

View File

@@ -0,0 +1,4 @@
---
# Source: reloader/templates/rolebinding.yaml

View File

@@ -0,0 +1,13 @@
---
# Source: reloader/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: reloader
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader

View File

@@ -1,16 +1,21 @@
---
# Source: reloader/templates/role.yaml
---
# Source: reloader/templates/deployment.yaml
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: reloader
group: com.stakater.platform
provider: stakater
version: 0.0.16
chart: "reloader-0.0.16"
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
group: com.stakater.platform
provider: stakater
version: v0.0.34
name: reloader
spec:
replicas: 1
@@ -18,46 +23,35 @@ spec:
selector:
matchLabels:
app: reloader
group: com.stakater.platform
provider: stakater
release: "RELEASE-NAME"
template:
metadata:
labels:
app: reloader
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
group: com.stakater.platform
provider: stakater
version: v0.0.34
spec:
containers:
- env:
image: "stakater/reloader:0.0.16"
image: "stakater/reloader:v0.0.34"
imagePullPolicy: IfNotPresent
name: reloader
serviceAccountName: reloader
---
# Source: reloader/templates/rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: reloader
group: com.stakater.platform
provider: stakater
version: 0.0.16
chart: "reloader-0.0.16"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader
---
# Source: reloader/templates/clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
labels:
app: reloader
group: com.stakater.platform
provider: stakater
version: 0.0.16
chart: "reloader-0.0.16"
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader-role
@@ -65,7 +59,7 @@ metadata:
rules:
- apiGroups:
- ""
resources:
resources:
- secrets
- configmaps
verbs:
@@ -73,8 +67,6 @@ rules:
- get
- watch
- apiGroups:
- ""
- "extensions"
- "apps"
resources:
- deployments
@@ -85,16 +77,30 @@ rules:
- get
- update
- patch
- apiGroups:
- "extensions"
resources:
- deployments
- daemonsets
verbs:
- list
- get
- update
- patch
---
# Source: reloader/templates/rolebinding.yaml
---
# Source: reloader/templates/clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
labels:
labels:
app: reloader
group: com.stakater.platform
provider: stakater
version: 0.0.16
chart: "reloader-0.0.16"
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader-role-binding
@@ -107,3 +113,17 @@ subjects:
- kind: ServiceAccount
name: reloader
namespace: default
---
# Source: reloader/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: reloader
chart: "reloader-v0.0.34"
release: "RELEASE-NAME"
heritage: "Tiller"
name: reloader

View File

@@ -4,10 +4,26 @@ apiVersion: v1
name: reloader
description: Reloader chart that runs on kubernetes
version: {{ getenv "VERSION" }}
appVersion: {{ getenv "VERSION" }}
keywords:
- Reloader
- kubernetes
home: https://github.com/stakater/Reloader
sources:
- https://github.com/stakater/IngressMonitorController
icon: https://raw.githubusercontent.com/stakater/Reloader/master/assets/web/reloader-round-100px.png
maintainers:
- name: Stakater
email: hello@stakater.com
email: hello@stakater.com
- name: rasheedamir
email: rasheed@aurorasolutions.io
- name: waseem-h
email: waseemhassan@stakater.com
- name: faizanahmad055
email: faizan.ahmad55@outlook.com
- name: kahootali
email: ali.kahoot@aurorasolutions.io
- name: ahmadiq
email: ahmad@aurorasolutions.io
- name: ahsan-storm
email: ahsanmuhammad1@outlook.com

View File

@@ -4,12 +4,76 @@ kubernetes:
host: https://kubernetes.default
reloader:
labels:
provider: stakater
group: com.stakater.platform
version: {{ getenv "VERSION" }}
image:
name: {{ getenv "DOCKER_IMAGE" }}
tag: "{{ getenv "VERSION" }}"
pullPolicy: IfNotPresent
watchGlobally: true
watchGlobally: true
# Set to true if you have a pod security policy that enforces readOnlyRootFilesystem
readOnlyRootFileSystem: false
matchLabels: {}
deployment:
nodeSelector:
# cloud.google.com/gke-nodepool: default-pool
# An affinity stanza to be applied to the Deployment.
# Example:
# affinity:
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
# - matchExpressions:
# - key: "node-role.kubernetes.io/infra-worker"
# operator: "Exists"
affinity: {}
# A list of tolerations to be applied to the Deployment.
# Example:
# tolerations:
# - key: "node-role.kubernetes.io/infra-worker"
# operator: "Exists"
# effect: "NoSchedule"
tolerations: []
annotations: {}
labels:
provider: stakater
group: com.stakater.platform
version: {{ getenv "VERSION" }}
image:
name: {{ getenv "DOCKER_IMAGE" }}
tag: "{{ getenv "VERSION" }}"
pullPolicy: IfNotPresent
# Support for extra environment variables.
env:
# Open supports Key value pair as environment variables.
open:
# secret supports Key value pair as environment variables. It gets the values based on keys from default reloader secret if any.
secret:
# field supports Key value pair as environment variables. It gets the values from other fields of pod.
field:
# Specify resource requests/limits for the deployment.
# Example:
# resources:
# limits:
# cpu: "100m"
# memory: "512Mi"
# requests:
# cpu: "10m"
# memory: "128Mi"
resources: {}
rbac:
enabled: true
labels: {}
# Service account config for the agent pods
serviceAccount:
# Specifies whether a ServiceAccount should be created
create: true
labels: {}
# The name of the ServiceAccount to use.
# If not set and create is true, a name is generated using the fullname template
name: reloader
# Optional flags to pass to the Reloader entrypoint
# Example:
# custom_annotations:
# configmap: "my.company.com/configmap"
# secret: "my.company.com/secret"
custom_annotations: {}

View File

@@ -1,6 +1,6 @@
# 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`.
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`, `Daemonset` and `Statefulset`.
## How change detection works
@@ -17,23 +17,25 @@ The annotation value is comma separated list of `configmaps` or `secrets`. If a
### Annotation for Configmap
For a `Deployment` called `foo` have a `ConfigMap` called `foo`. Then add this annotation to your `Deployment`
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"
```
<small>*the default annotation can be changed with the `--configmap-annotation` flag</small>
### Annotation for Secret
For a `Deployment` called `foo` have a `Secret` called `foo`. Then add this annotation to your `Deployment`
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"
```
<small>*the default annotation can be changed with the `--secret-annotation` flag</small>
Above mentioned annotation are also work for `Daemonsets` and `Statefulsets`
@@ -75,3 +77,6 @@ And render manifest file using helm command
helm --namespace {replace this with namespace name} template . > reloader.yaml
```
The output file can then be used to deploy reloader in specific namespace.
## Compatibility with helm install and upgrade
Reloader has no impact on helm deployment cycle. Reloader only injects an environment variable in `deployment`, `daemonset` or `statefulset`. The environment variable contains the SHA1 value of configmap's or secret's data. So if a deployment is created using Helm and Reloader updates the deployment, then next time you upgrade the helm release, reloader will do nothing except changing that environment variable value in `deployment` , `daemonset` or `statefulset`.

View File

@@ -8,4 +8,5 @@ Reloader is inspired from [Configmapcontroller](https://github.com/fabric8io/con
| Reloader can watch both `secrets` and `configmaps`. | ConfigmapController can only watch changes in `configmaps`. It cannot detect changes in other resources like `secrets`. |
| Reloader can perform rolling upgrades on `deployments` as well as on `statefulsets` and `daemonsets` | ConfigmapController can only perform rolling upgrades on `deployments`. It currently does not support rolling upgrades on `statefulsets` and `daemonsets` |
| Reloader provides both unit test cases and end to end integration test cases for future updates. So one can make sure that new changes do not break any old functionality. | Currently there are not any unit test cases or end to end integration test cases in configmap controller. It add difficulties for any additional updates in configmap controller and one can not know for sure whether new changes breaks any old functionality or not. |
| Reloader uses SHA1 to encode the change in configmap or secret. It then saves the SHA1 value in `STAKATER_FOO_CONFIGMAP` or `STAKATER_FOO_SECRET` environment variable depending upon where the change has happened. The use of SHA1 provides a concise 40 characters encoded value that is very less pron to collision. | Configmap controller uses `FABRICB_FOO_REVISION` environment variable to store any change in configmap controller. It does not encode it or convert it in suitable hash value to avoid data pollution in deployment. |
| Reloader uses SHA1 to encode the change in configmap or secret. It then saves the SHA1 value in `STAKATER_FOO_CONFIGMAP` or `STAKATER_FOO_SECRET` environment variable depending upon where the change has happened. The use of SHA1 provides a concise 40 characters encoded value that is very less pron to collision. | Configmap controller uses `FABRICB_FOO_REVISION` environment variable to store any change in configmap controller. It does not encode it or convert it in suitable hash value to avoid data pollution in deployment. |
| Reloader allows you to customize your own annotation (for both Secrets and Configmaps) using command line flags | Configmap controller restricts you to only their provided annotation |

View File

@@ -25,4 +25,16 @@ Reloader supports deployment rollout as well as daemonsets and statefulsets roll
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]`
Reloader stores the hash value in an environment variable `STAKATER_NAME_[SECRET|CONFIGMAP]`
### Customization
#### k8s-trigger-controller:
k8s-trigger-controller restricts you to using the `trigger.k8s.io/[secret-configMap]-NAME-last-hash` annotation
#### Reloader:
Reloader allows you to customize the annotation to fit your needs with command line flags:
- `--auto-annotation <annotation>`
- `--configmap-annotation <annotation>`
- `--secret-annotation <annotation>`

View File

@@ -0,0 +1,11 @@
Below are the steps to use reloader with Sealed Secrets.
1. Download and install the kubeseal client from [here](https://github.com/bitnami-labs/sealed-secrets).
2. Install the controller for sealed secrets
3. Fetch the encryption certificate
4. Encrypt the secret.
5. Apply the secret.
7. Install the tool which uses that sealed secret.
8. Install Reloader.
9. Once everything is setup, update the original secret at client and encrypt it with kubeseal to see reloader working.
10. Apply the updated sealed secret.
11. Reloader will resatart the pod to use that updated secret.

View File

@@ -1,11 +1,11 @@
package: github.com/stakater/Reloader
import:
- package: k8s.io/api
version: kubernetes-1.8.0
version: kubernetes-1.10.0
- package: k8s.io/apimachinery
version: kubernetes-1.8.0
version: kubernetes-1.10.0
- package: k8s.io/client-go
version: 5.0.0
version: 6.0.0
- package: github.com/spf13/cobra
version: 0.0.3
- package: github.com/spf13/pflag

View File

@@ -4,7 +4,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/stakater/Reloader/internal/pkg/util"
apps_v1beta1 "k8s.io/api/apps/v1beta1"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
@@ -16,15 +16,23 @@ type ItemsFunc func(kubernetes.Interface, string) []interface{}
//ContainersFunc is a generic func to return containers
type ContainersFunc func(interface{}) []v1.Container
//InitContainersFunc is a generic func to return containers
type InitContainersFunc 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
//RollingUpgradeFuncs contains generic functions to perform rolling upgrade
type RollingUpgradeFuncs struct {
ItemsFunc ItemsFunc
ContainersFunc ContainersFunc
UpdateFunc UpdateFunc
ResourceType string
ItemsFunc ItemsFunc
ContainersFunc ContainersFunc
InitContainersFunc InitContainersFunc
UpdateFunc UpdateFunc
VolumesFunc VolumesFunc
ResourceType string
}
// GetDeploymentItems returns the deployments in given namespace
@@ -69,6 +77,21 @@ func GetStatefulsetContainers(item interface{}) []v1.Container {
return item.(apps_v1beta1.StatefulSet).Spec.Template.Spec.Containers
}
// GetDeploymentInitContainers returns the containers of given deployment
func GetDeploymentInitContainers(item interface{}) []v1.Container {
return item.(v1beta1.Deployment).Spec.Template.Spec.InitContainers
}
// GetDaemonSetInitContainers returns the containers of given daemonset
func GetDaemonSetInitContainers(item interface{}) []v1.Container {
return item.(v1beta1.DaemonSet).Spec.Template.Spec.InitContainers
}
// GetStatefulsetInitContainers returns the containers of given statefulSet
func GetStatefulsetInitContainers(item interface{}) []v1.Container {
return item.(apps_v1beta1.StatefulSet).Spec.Template.Spec.InitContainers
}
// UpdateDeployment performs rolling upgrade on deployment
func UpdateDeployment(client kubernetes.Interface, namespace string, resource interface{}) error {
deployment := resource.(v1beta1.Deployment)
@@ -89,3 +112,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
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/stakater/Reloader/internal/pkg/controller"
"github.com/stakater/Reloader/internal/pkg/options"
"github.com/stakater/Reloader/pkg/kube"
"k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -17,6 +18,12 @@ func NewReloaderCommand() *cobra.Command {
Short: "A watcher for your Kubernetes cluster",
Run: startReloader,
}
// options
cmd.PersistentFlags().StringVar(&options.ConfigmapUpdateOnChangeAnnotation, "configmap-annotation", "configmap.reloader.stakater.com/reload", "annotation to detect changes in configmaps")
cmd.PersistentFlags().StringVar(&options.SecretUpdateOnChangeAnnotation, "secret-annotation", "secret.reloader.stakater.com/reload", "annotation to detect changes in secrets")
cmd.PersistentFlags().StringVar(&options.ReloaderAutoAnnotation, "auto-annotation", "reloader.stakater.com/auto", "annotation to detect changes in secrets")
return cmd
}
@@ -43,7 +50,7 @@ func startReloader(cmd *cobra.Command, args []string) {
// Now let's start the controller
stop := make(chan struct{})
defer close(stop)
logrus.Infof("Starting Controller to watch resource type: %s", k)
go c.Run(1, stop)
}

View 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
)

View File

@@ -64,13 +64,11 @@ 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
func (c *Controller) Run(threadiness int, stopCh chan struct{}) {
logrus.Infof("Starting Controller")
defer runtime.HandleCrash()
// Let the workers stop when we are done

View File

@@ -6,8 +6,9 @@ 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/options"
"github.com/stakater/Reloader/internal/pkg/testutil"
"github.com/stakater/Reloader/internal/pkg/util"
"github.com/stakater/Reloader/pkg/kube"
@@ -60,7 +61,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)
}
@@ -78,14 +79,122 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDeployment(t *testing.T) {
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
Annotation: options.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: options.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: options.ConfigmapUpdateOnChangeAnnotation,
}
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
if !updated {
t.Errorf("Deployment was not updated")
@@ -116,7 +225,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)
}
@@ -140,15 +249,10 @@ func TestControllerForUpdatingConfigmapShouldUpdateDeployment(t *testing.T) {
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
Annotation: options.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 +284,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)
}
@@ -198,14 +302,9 @@ func TestControllerUpdatingConfigmapLabelsShouldNotCreateorUpdateEnvInDeployment
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceType: "Deployment",
Annotation: options.ConfigmapUpdateOnChangeAnnotation,
}
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 +325,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: options.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 +394,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)
}
@@ -254,14 +412,9 @@ func TestControllerUpdatingSecretShouldCreateEnvInDeployment(t *testing.T) {
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceType: "Deployment",
Annotation: options.SecretUpdateOnChangeAnnotation,
}
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
if !updated {
t.Errorf("Deployment was not updated")
@@ -291,7 +444,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)
}
@@ -315,14 +468,9 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDeployment(t *testing.T) {
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceType: "Deployment",
Annotation: options.SecretUpdateOnChangeAnnotation,
}
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, deploymentFuncs)
if !updated {
t.Errorf("Deployment was not updated")
@@ -342,7 +490,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 +500,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)
}
@@ -369,14 +517,9 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDeployment(t
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
deploymentFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDeploymentItems,
ContainersFunc: callbacks.GetDeploymentContainers,
UpdateFunc: callbacks.UpdateDeployment,
ResourceType: "Deployment",
Annotation: options.SecretUpdateOnChangeAnnotation,
}
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 +549,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)
}
@@ -424,14 +567,9 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInDaemonSet(t *testing.T) {
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceType: "DaemonSet",
Annotation: options.ConfigmapUpdateOnChangeAnnotation,
}
daemonSetFuncs := handler.GetDaemonSetRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
@@ -462,7 +600,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 +611,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")
@@ -486,14 +628,9 @@ func TestControllerForUpdatingConfigmapShouldUpdateDaemonSet(t *testing.T) {
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceType: "DaemonSet",
Annotation: options.ConfigmapUpdateOnChangeAnnotation,
}
daemonSetFuncs := handler.GetDaemonSetRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
@@ -514,7 +651,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 +661,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)
}
@@ -542,14 +679,9 @@ func TestControllerUpdatingSecretShouldCreateEnvInDaemonSet(t *testing.T) {
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceType: "DaemonSet",
Annotation: options.SecretUpdateOnChangeAnnotation,
}
daemonSetFuncs := handler.GetDaemonSetRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
@@ -579,7 +711,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)
}
@@ -604,14 +736,9 @@ func TestControllerUpdatingSecretShouldUpdateEnvInDaemonSet(t *testing.T) {
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceType: "DaemonSet",
Annotation: options.SecretUpdateOnChangeAnnotation,
}
daemonSetFuncs := handler.GetDaemonSetRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, daemonSetFuncs)
if !updated {
t.Errorf("DaemonSet was not updated")
@@ -631,7 +758,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 +768,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)
}
@@ -658,14 +785,9 @@ func TestControllerUpdatingSecretLabelsShouldNotCreateorUpdateEnvInDaemonSet(t *
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
daemonSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetDaemonSetItems,
ContainersFunc: callbacks.GetDaemonSetContainers,
UpdateFunc: callbacks.UpdateDaemonSet,
ResourceType: "DaemonSet",
Annotation: options.SecretUpdateOnChangeAnnotation,
}
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 +817,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)
}
@@ -713,14 +835,9 @@ func TestControllerUpdatingConfigmapShouldCreateEnvInStatefulSet(t *testing.T) {
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceType: "StatefulSet",
Annotation: options.ConfigmapUpdateOnChangeAnnotation,
}
statefulSetFuncs := handler.GetStatefulSetRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")
@@ -751,7 +868,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)
}
@@ -775,14 +892,9 @@ func TestControllerForUpdatingConfigmapShouldUpdateStatefulSet(t *testing.T) {
Namespace: namespace,
ResourceName: configmapName,
SHAValue: shaData,
Annotation: constants.ConfigmapUpdateOnChangeAnnotation,
}
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceType: "StatefulSet",
Annotation: options.ConfigmapUpdateOnChangeAnnotation,
}
statefulSetFuncs := handler.GetStatefulSetRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.ConfigmapEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")
@@ -803,7 +915,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 +925,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)
}
@@ -831,14 +943,9 @@ func TestControllerUpdatingSecretShouldCreateEnvInStatefulSet(t *testing.T) {
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceType: "StatefulSet",
Annotation: options.SecretUpdateOnChangeAnnotation,
}
statefulSetFuncs := handler.GetStatefulSetRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")
@@ -868,7 +975,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)
}
@@ -892,14 +999,9 @@ func TestControllerUpdatingSecretShouldUpdateEnvInStatefulSet(t *testing.T) {
Namespace: namespace,
ResourceName: secretName,
SHAValue: shaData,
Annotation: constants.SecretUpdateOnChangeAnnotation,
}
statefulSetFuncs := callbacks.RollingUpgradeFuncs{
ItemsFunc: callbacks.GetStatefulSetItems,
ContainersFunc: callbacks.GetStatefulsetContainers,
UpdateFunc: callbacks.UpdateStatefulset,
ResourceType: "StatefulSet",
Annotation: options.SecretUpdateOnChangeAnnotation,
}
statefulSetFuncs := handler.GetStatefulSetRollingUpgradeFuncs()
updated := testutil.VerifyResourceUpdate(client, config, constants.SecretEnvVarPostfix, statefulSetFuncs)
if !updated {
t.Errorf("StatefulSet was not updated")

View File

@@ -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,24 @@ type ResourceCreatedHandler struct {
func (r ResourceCreatedHandler) Handle() error {
if r.Resource == nil {
logrus.Errorf("Resource creation handler received nil resource")
} else {
config, _ := r.GetConfig()
// 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
}

View File

@@ -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)
}

View File

@@ -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"
"k8s.io/api/core/v1"
)
// ResourceUpdatedHandler contains updated objects
@@ -25,162 +17,27 @@ 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)
// 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
}

View File

@@ -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")
}
}

View File

@@ -0,0 +1,238 @@
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/options"
"github.com/stakater/Reloader/internal/pkg/util"
"github.com/stakater/Reloader/pkg/kube"
v1 "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,
InitContainersFunc: callbacks.GetDeploymentInitContainers,
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,
InitContainersFunc: callbacks.GetDaemonSetInitContainers,
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,
InitContainersFunc: callbacks.GetStatefulsetInitContainers,
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 {
// find correct annotation and update the resource
annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation]
reloaderEnabledValue := util.ToObjectMeta(i).Annotations[options.ReloaderAutoAnnotation]
result := constants.NotUpdated
reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue)
if err == nil && reloaderEnabled {
result = updateContainers(upgradeFuncs, i, config, true)
}
if result != constants.Updated && annotationValue != "" {
values := strings.Split(annotationValue, ",")
for _, value := range values {
if value == config.ResourceName {
result = updateContainers(upgradeFuncs, i, config, false)
if result == constants.Updated {
break
}
}
}
}
if result == constants.Updated {
err = upgradeFuncs.UpdateFunc(client, config.Namespace, i)
resourceName := util.ToObjectMeta(i).Name
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("Changes detected in '%s' of type '%s' in namespace '%s'", config.ResourceName, config.Type, config.Namespace)
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 getContainerWithVolumeMount(containers []v1.Container, volumeMountName string) *v1.Container {
for i := range containers {
volumeMounts := containers[i].VolumeMounts
for j := range volumeMounts {
if volumeMounts[j].Name == volumeMountName {
return &containers[i]
}
}
}
return nil
}
func getContainerWithEnvReference(containers []v1.Container, resourceName string, resourceType string) *v1.Container {
for i := range containers {
envs := containers[i].Env
for j := range envs {
envVarSource := envs[j].ValueFrom
if envVarSource != nil {
if resourceType == constants.SecretEnvVarPostfix && envVarSource.SecretKeyRef != nil && envVarSource.SecretKeyRef.LocalObjectReference.Name == resourceName {
return &containers[i]
} else if resourceType == constants.ConfigmapEnvVarPostfix && envVarSource.ConfigMapKeyRef != nil && envVarSource.ConfigMapKeyRef.LocalObjectReference.Name == resourceName {
return &containers[i]
}
}
}
envsFrom := containers[i].EnvFrom
for j := range envsFrom {
if resourceType == constants.SecretEnvVarPostfix && envsFrom[j].SecretRef != nil && envsFrom[j].SecretRef.LocalObjectReference.Name == resourceName {
return &containers[i]
} else if resourceType == constants.ConfigmapEnvVarPostfix && envsFrom[j].ConfigMapRef != nil && envsFrom[j].ConfigMapRef.LocalObjectReference.Name == resourceName {
return &containers[i]
}
}
}
return nil
}
func getContainerToUpdate(upgradeFuncs callbacks.RollingUpgradeFuncs, item interface{}, config util.Config, autoReload bool) *v1.Container {
volumes := upgradeFuncs.VolumesFunc(item)
containers := upgradeFuncs.ContainersFunc(item)
initContainers := upgradeFuncs.InitContainersFunc(item)
var container *v1.Container
// Get the volumeMountName to find volumeMount in container
volumeMountName := getVolumeMountName(volumes, config.Type, config.ResourceName)
// Get the container with mounted configmap/secret
if volumeMountName != "" {
container = getContainerWithVolumeMount(containers, volumeMountName)
if container == nil && len(initContainers) > 0 {
container = getContainerWithVolumeMount(initContainers, volumeMountName)
if container != nil {
// if configmap/secret is being used in init container then return the first Pod container to save reloader env
return &containers[0]
}
} else if container != nil {
return container
}
}
// Get the container with referenced secret or configmap as env var
container = getContainerWithEnvReference(containers, config.ResourceName, config.Type)
if container == nil && len(initContainers) > 0 {
container = getContainerWithEnvReference(initContainers, config.ResourceName, config.Type)
if container != nil {
// if configmap/secret is being used in init container then return the first Pod container to save reloader env
return &containers[0]
}
}
// Get the first container if the annotation is related to specified configmap or secret i.e. configmap.reloader.stakater.com/reload
if container == nil && !autoReload {
return &containers[0]
}
return container
}
func updateContainers(upgradeFuncs callbacks.RollingUpgradeFuncs, item interface{}, config util.Config, autoReload bool) constants.Result {
var result constants.Result
envar := constants.EnvVarPrefix + util.ConvertToEnvVarName(config.ResourceName) + "_" + config.Type
container := getContainerToUpdate(upgradeFuncs, item, config, autoReload)
if container == nil {
return constants.NoContainerFound
}
//update if env var exists
result = updateEnvVar(upgradeFuncs.ContainersFunc(item), 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
}

View File

@@ -0,0 +1,668 @@
package handler
import (
"os"
"testing"
"time"
"github.com/sirupsen/logrus"
"github.com/stakater/Reloader/internal/pkg/constants"
"github.com/stakater/Reloader/internal/pkg/options"
"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)
configmapWithInitContainer = "testconfigmapInitContainerhandler-" + testutil.RandSeq(3)
secretWithInitContainer = "testsecretWithInitContainer-handler-" + testutil.RandSeq(3)
configmapWithInitEnv = "configmapWithInitEnv-" + testutil.RandSeq(3)
secretWithInitEnv = "secretWithInitEnv-handler-" + testutil.RandSeq(3)
configmapWithEnvName = "testconfigmapWithEnv-handler-" + testutil.RandSeq(3)
configmapWithEnvFromName = "testconfigmapWithEnvFrom-handler-" + testutil.RandSeq(3)
secretWithEnvName = "testsecretWithEnv-handler-" + testutil.RandSeq(5)
secretWithEnvFromName = "testsecretWithEnvFrom-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)
}
_, err = testutil.CreateConfigMap(client, namespace, configmapWithEnvFromName, "www.google.com")
if err != nil {
logrus.Errorf("Error in configmap creation: %v", err)
}
// Creating secret
_, err = testutil.CreateSecret(client, namespace, secretWithInitEnv, data)
if err != nil {
logrus.Errorf("Error in secret creation: %v", err)
}
_, err = testutil.CreateConfigMap(client, namespace, configmapWithInitContainer, "www.google.com")
if err != nil {
logrus.Errorf("Error in configmap creation: %v", err)
}
// Creating secret
_, err = testutil.CreateSecret(client, namespace, secretWithEnvFromName, data)
if err != nil {
logrus.Errorf("Error in secret creation: %v", err)
}
_, err = testutil.CreateConfigMap(client, namespace, configmapWithInitContainer, "www.google.com")
if err != nil {
logrus.Errorf("Error in configmap creation: %v", err)
}
// Creating secret
_, err = testutil.CreateSecret(client, namespace, secretWithInitContainer, 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 configmap mounted in init container
_, err = testutil.CreateDeploymentWithInitContainer(client, configmapWithInitContainer, namespace, true)
if err != nil {
logrus.Errorf("Error in Deployment with configmap creation: %v", err)
}
// Creating Deployment with secret mounted in init container
_, err = testutil.CreateDeploymentWithInitContainer(client, secretWithInitContainer, namespace, true)
if err != nil {
logrus.Errorf("Error in Deployment with secret creation: %v", err)
}
// Creating Deployment with configmap mounted as Env in init container
_, err = testutil.CreateDeploymentWithInitContainer(client, configmapWithInitEnv, namespace, false)
if err != nil {
logrus.Errorf("Error in Deployment with configmap creation: %v", err)
}
// Creating Deployment with secret mounted as Env in init container
_, err = testutil.CreateDeploymentWithInitContainer(client, secretWithInitEnv, namespace, false)
if err != nil {
logrus.Errorf("Error in Deployment with secret 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 Deployment with envFrom source as secret
_, err = testutil.CreateDeploymentWithEnvVarSource(client, configmapWithEnvFromName, namespace)
if err != nil {
logrus.Errorf("Error in Deployment with secret configmap as envFrom source creation: %v", err)
}
// Creating Deployment with envFrom source as secret
_, err = testutil.CreateDeploymentWithEnvVarSource(client, secretWithEnvFromName, namespace)
if err != nil {
logrus.Errorf("Error in Deployment with secret configmap as envFrom 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 Deployment with configmap mounted in init container
deploymentError = testutil.DeleteDeployment(client, namespace, configmapWithInitContainer)
if deploymentError != nil {
logrus.Errorf("Error while deleting deployment with configmap mounted in init container %v", deploymentError)
}
// Deleting Deployment with secret mounted in init container
deploymentError = testutil.DeleteDeployment(client, namespace, secretWithInitContainer)
if deploymentError != nil {
logrus.Errorf("Error while deleting deployment with secret mounted in init container %v", deploymentError)
}
// Deleting Deployment with configmap mounted as env in init container
deploymentError = testutil.DeleteDeployment(client, namespace, configmapWithInitEnv)
if deploymentError != nil {
logrus.Errorf("Error while deleting deployment with configmap mounted as env in init container %v", deploymentError)
}
// Deleting Deployment with secret mounted as env in init container
deploymentError = testutil.DeleteDeployment(client, namespace, secretWithInitEnv)
if deploymentError != nil {
logrus.Errorf("Error while deleting deployment with secret mounted as env in init container %v", deploymentError)
}
// Deleting Deployment with configmap as envFrom source
deploymentError = testutil.DeleteDeployment(client, namespace, configmapWithEnvFromName)
if deploymentError != nil {
logrus.Errorf("Error while deleting deployment with configmap as envFrom source %v", deploymentError)
}
// Deleting Deployment with secret as envFrom source
deploymentError = testutil.DeleteDeployment(client, namespace, secretWithEnvFromName)
if deploymentError != nil {
logrus.Errorf("Error while deleting deployment with secret as envFrom 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 Configmap used in init container
err = testutil.DeleteConfigMap(client, namespace, configmapWithInitContainer)
if err != nil {
logrus.Errorf("Error while deleting the configmap used in init container %v", err)
}
// Deleting Secret used in init container
err = testutil.DeleteSecret(client, namespace, secretWithInitContainer)
if err != nil {
logrus.Errorf("Error while deleting the secret used in init container %v", err)
}
// Deleting Configmap used as env var source
err = testutil.DeleteConfigMap(client, namespace, configmapWithEnvFromName)
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, secretWithEnvFromName)
if err != nil {
logrus.Errorf("Error while deleting the secret used as env var source %v", err)
}
// Deleting Configmap used as env var source
err = testutil.DeleteConfigMap(client, namespace, configmapWithInitEnv)
if err != nil {
logrus.Errorf("Error while deleting the configmap used as env var source in init container %v", err)
}
// Deleting Secret used as env var source
err = testutil.DeleteSecret(client, namespace, secretWithInitEnv)
if err != nil {
logrus.Errorf("Error while deleting the secret used as env var source in init container %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, options.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 TestRollingUpgradeForDeploymentWithConfigmapInInitContainer(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapWithInitContainer, "www.stakater.com")
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapWithInitContainer, shaData, options.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, options.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 TestRollingUpgradeForDeploymentWithConfigmapAsEnvVarInInitContainer(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapWithInitEnv, "www.stakater.com")
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapWithInitEnv, shaData, options.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 TestRollingUpgradeForDeploymentWithConfigmapAsEnvVarFrom(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, namespace, configmapWithEnvFromName, "www.stakater.com")
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, configmapWithEnvFromName, shaData, options.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, options.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 TestRollingUpgradeForDeploymentWithSecretinInitContainer(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretWithInitContainer, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy")
config := getConfigWithAnnotations(constants.SecretEnvVarPostfix, secretWithInitContainer, shaData, options.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, options.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 TestRollingUpgradeForDeploymentWithSecretAsEnvVarFrom(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretWithEnvFromName, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy")
config := getConfigWithAnnotations(constants.SecretEnvVarPostfix, secretWithEnvFromName, shaData, options.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 TestRollingUpgradeForDeploymentWithSecretAsEnvVarInInitContainer(t *testing.T) {
shaData := testutil.ConvertResourceToSHA(testutil.SecretResourceType, namespace, secretWithInitEnv, "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy")
config := getConfigWithAnnotations(constants.SecretEnvVarPostfix, secretWithInitEnv, shaData, options.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, options.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, options.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, options.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, options.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, options.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")
}
}

View File

@@ -1,8 +1,10 @@
package constants
package options
const (
var (
// ConfigmapUpdateOnChangeAnnotation is an annotation to detect changes in configmaps
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"
)

View File

@@ -3,6 +3,7 @@ package testutil
import (
"math/rand"
"sort"
"strconv"
"strings"
"time"
@@ -10,10 +11,11 @@ import (
"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/options"
"github.com/stakater/Reloader/internal/pkg/util"
"github.com/stakater/Reloader/pkg/kube"
v1_beta1 "k8s.io/api/apps/v1beta1"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
@@ -40,7 +42,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 +52,300 @@ 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{
options.ReloaderAutoAnnotation: "true"}
}
return map[string]string{
options.ConfigmapUpdateOnChangeAnnotation: name,
options.SecretUpdateOnChangeAnnotation: name}
}
func getEnvVarSources(name string) []v1.EnvFromSource {
return []v1.EnvFromSource{
{
ConfigMapRef: &v1.ConfigMapEnvSource{
LocalObjectReference: v1.LocalObjectReference{
Name: name,
},
},
},
{
SecretRef: &v1.SecretEnvSource{
LocalObjectReference: v1.LocalObjectReference{
Name: name,
},
},
},
}
}
func getVolumes(name string) []v1.Volume {
return []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,
},
},
},
}
}
func getVolumeMounts(name string) []v1.VolumeMount {
return []v1.VolumeMount{
{
MountPath: "etc/config",
Name: "configmap",
},
{
MountPath: "etc/sec",
Name: "secret",
},
}
}
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 getPodTemplateSpecWithEnvVarSources(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,
EnvFrom: getEnvVarSources(name),
},
},
},
}
}
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: getVolumeMounts(name),
},
},
Volumes: getVolumes(name),
},
}
}
func getPodTemplateSpecWithInitContainer(name string) v1.PodTemplateSpec {
return v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"secondLabel": "temp"},
},
Spec: v1.PodSpec{
InitContainers: []v1.Container{
{
Image: "busybox",
Name: "busyBox",
VolumeMounts: getVolumeMounts(name),
},
},
Containers: []v1.Container{
{
Image: "tutum/hello-world",
Name: name,
Env: []v1.EnvVar{
{
Name: "BUCKET_NAME",
Value: "test",
},
},
},
},
Volumes: getVolumes(name),
},
}
}
func getPodTemplateSpecWithInitContainerAndEnv(name string) v1.PodTemplateSpec {
return v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"secondLabel": "temp"},
},
Spec: v1.PodSpec{
InitContainers: []v1.Container{
{
Image: "busybox",
Name: "busyBox",
EnvFrom: getEnvVarSources(name),
},
},
Containers: []v1.Container{
{
Image: "tutum/hello-world",
Name: name,
Env: []v1.EnvVar{
{
Name: "BUCKET_NAME",
Value: "test",
},
},
},
},
},
}
}
// 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),
},
}
}
// GetDeploymentWithInitContainer provides deployment with init container and volumeMounts
func GetDeploymentWithInitContainer(namespace string, deploymentName string) *v1beta1.Deployment {
replicaset := int32(1)
return &v1beta1.Deployment{
ObjectMeta: getObjectMeta(namespace, deploymentName, false),
Spec: v1beta1.DeploymentSpec{
Replicas: &replicaset,
Strategy: v1beta1.DeploymentStrategy{
Type: v1beta1.RollingUpdateDeploymentStrategyType,
},
Template: getPodTemplateSpecWithInitContainer(deploymentName),
},
}
}
// GetDeploymentWithInitContainerAndEnv provides deployment with init container and EnvSource
func GetDeploymentWithInitContainerAndEnv(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: getPodTemplateSpecWithInitContainerAndEnv(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),
},
}
}
func GetDeploymentWithEnvVarSources(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: getPodTemplateSpecWithEnvVarSources(deploymentName),
},
}
}
@@ -99,37 +353,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 +378,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 +499,71 @@ 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
}
// CreateDeploymentWithInitContainer creates a deployment in given namespace with init container and returns the Deployment
func CreateDeploymentWithInitContainer(client kubernetes.Interface, deploymentName string, namespace string, volumeMount bool) (*v1beta1.Deployment, error) {
logrus.Infof("Creating Deployment")
deploymentClient := client.ExtensionsV1beta1().Deployments(namespace)
var deploymentObj *v1beta1.Deployment
if volumeMount {
deploymentObj = GetDeploymentWithInitContainer(namespace, deploymentName)
} else {
deploymentObj = GetDeploymentWithInitContainerAndEnv(namespace, deploymentName)
}
deployment, err := deploymentClient.Create(deploymentObj)
time.Sleep(10 * time.Second)
return deployment, err
}
// CreateDeploymentWithEnvVarSource creates a deployment in given namespace and returns the Deployment
func CreateDeploymentWithEnvVarSource(client kubernetes.Interface, deploymentName string, namespace string) (*v1beta1.Deployment, error) {
logrus.Infof("Creating Deployment")
deploymentClient := client.ExtensionsV1beta1().Deployments(namespace)
deploymentObj := GetDeploymentWithEnvVarSources(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 +646,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[options.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
}
}
}

View File

@@ -1,9 +1,38 @@
package util
import (
"github.com/stakater/Reloader/internal/pkg/constants"
"github.com/stakater/Reloader/internal/pkg/options"
v1 "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: options.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: options.SecretUpdateOnChangeAnnotation,
SHAValue: GetSHAfromSecret(secret.Data),
Type: constants.SecretEnvVarPostfix,
}
}

View File

@@ -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
}

View File

@@ -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, ";"))
}