mirror of
https://github.com/stakater/Reloader.git
synced 2026-02-14 18:09:50 +00:00
Compare commits
122 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f331907d3 | ||
|
|
29aa52a1c7 | ||
|
|
ada8dbb5f3 | ||
|
|
cfe1754c44 | ||
|
|
2cfce5144b | ||
|
|
2fe863a054 | ||
|
|
3e01091d01 | ||
|
|
7f85a8e53b | ||
|
|
c679157e24 | ||
|
|
9e7b70964e | ||
|
|
8ebbb476b2 | ||
|
|
9263b812eb | ||
|
|
f70dd52b2d | ||
|
|
e0a8f1ad04 | ||
|
|
45dac417cb | ||
|
|
1514c5bcd2 | ||
|
|
e7cfafd6d6 | ||
|
|
15d7263c95 | ||
|
|
de21a400ab | ||
|
|
e702610dc6 | ||
|
|
481eeeffc4 | ||
|
|
801e1dabed | ||
|
|
5c44c1e8f5 | ||
|
|
0ef6dcb510 | ||
|
|
0ef5e75673 | ||
|
|
e5f85ae37b | ||
|
|
5d0e9ca70b | ||
|
|
297baa08d5 | ||
|
|
dd1433a7a9 | ||
|
|
9875c416df | ||
|
|
b414e3b350 | ||
|
|
e417e8bc12 | ||
|
|
aafe3365eb | ||
|
|
694baf715c | ||
|
|
48b188d7b4 | ||
|
|
d1cb53b65a | ||
|
|
cefd633176 | ||
|
|
08e6f81a15 | ||
|
|
edbad45637 | ||
|
|
363fbd3b77 | ||
|
|
82ee3ef3d1 | ||
|
|
21502e2bb4 | ||
|
|
9d3b70d4d2 | ||
|
|
5662919f72 | ||
|
|
445d0f870e | ||
|
|
81e74fe830 | ||
|
|
50791ad51a | ||
|
|
6a65657e27 | ||
|
|
1c7190884a | ||
|
|
e0fcc3bfa6 | ||
|
|
504b5a8eb0 | ||
|
|
488eaa9bef | ||
|
|
676c3703aa | ||
|
|
deec4df125 | ||
|
|
eedc8e81d0 | ||
|
|
28456ffafe | ||
|
|
a7c3ae37aa | ||
|
|
d043bcf7be | ||
|
|
72a1c59cac | ||
|
|
6299b1d8e9 | ||
|
|
11ae057b0a | ||
|
|
d34c99baf4 | ||
|
|
b7e83b74d8 | ||
|
|
919f75bb62 | ||
|
|
16079bd1d4 | ||
|
|
401d4227d1 | ||
|
|
7f9f32ca58 | ||
|
|
6937b8120b | ||
|
|
be80ce35b2 | ||
|
|
99349ce361 | ||
|
|
3a1b808169 | ||
|
|
798079eb53 | ||
|
|
98749f2c9b | ||
|
|
3a675696cd | ||
|
|
632eeaa527 | ||
|
|
9c85ce404b | ||
|
|
f8f8afca88 | ||
|
|
11dc048709 | ||
|
|
328442c121 | ||
|
|
4304880b6b | ||
|
|
aef99a7bb8 | ||
|
|
e387b21ed6 | ||
|
|
b6de33d501 | ||
|
|
48160e0414 | ||
|
|
d998c1a19e | ||
|
|
0b7ca82218 | ||
|
|
88fe843285 | ||
|
|
cf31fed9d3 | ||
|
|
ba7f7537fb | ||
|
|
499ecf9da5 | ||
|
|
6188811b94 | ||
|
|
0f2395309f | ||
|
|
41d4fa56ca | ||
|
|
bf21677357 | ||
|
|
c58d0965d5 | ||
|
|
ec1f7a68de | ||
|
|
68a353d097 | ||
|
|
c82886c921 | ||
|
|
4b9844f5c3 | ||
|
|
1e4016587c | ||
|
|
198e5631d4 | ||
|
|
f21ad29188 | ||
|
|
cd7ec500a7 | ||
|
|
030e51351a | ||
|
|
8703c150e0 | ||
|
|
1d7192180f | ||
|
|
9d1733200a | ||
|
|
841db3c829 | ||
|
|
1155c981d6 | ||
|
|
d29c99ffef | ||
|
|
3b572568be | ||
|
|
3e5b1d09b8 | ||
|
|
61b7a88462 | ||
|
|
d9d986f1f2 | ||
|
|
42a25bfe64 | ||
|
|
df667b9c15 | ||
|
|
f1c71731d9 | ||
|
|
e2b14ab7b5 | ||
|
|
4592bd4331 | ||
|
|
e380fbaf03 | ||
|
|
2bce1352a3 | ||
|
|
5b3b617f06 |
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
11
.github/workflows/pull_request.yaml
vendored
11
.github/workflows/pull_request.yaml
vendored
@@ -7,9 +7,9 @@ on:
|
||||
|
||||
env:
|
||||
DOCKER_FILE_PATH: Dockerfile
|
||||
GOLANG_VERSION: 1.17.2
|
||||
GOLANG_VERSION: 1.19.5
|
||||
KUBERNETES_VERSION: "1.18.0"
|
||||
KIND_VERSION: "0.7.0"
|
||||
KIND_VERSION: "0.10.0"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
# Setting up helm binary
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v1
|
||||
uses: azure/setup-helm@v3.4
|
||||
|
||||
- name: Set up Go
|
||||
id: go
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2.3.0
|
||||
with:
|
||||
version: v1.33
|
||||
version: v1.45.2
|
||||
only-new-issues: false
|
||||
args: --timeout 10m
|
||||
|
||||
@@ -48,6 +48,9 @@ jobs:
|
||||
cd deployments/kubernetes/chart/reloader
|
||||
helm lint
|
||||
|
||||
- name: Link check
|
||||
uses: gaurav-nelson/github-action-markdown-link-check@v1
|
||||
|
||||
- name: Install kubectl
|
||||
run: |
|
||||
curl -LO "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl"
|
||||
|
||||
16
.github/workflows/push.yaml
vendored
16
.github/workflows/push.yaml
vendored
@@ -7,9 +7,9 @@ on:
|
||||
|
||||
env:
|
||||
DOCKER_FILE_PATH: Dockerfile
|
||||
GOLANG_VERSION: 1.17.2
|
||||
GOLANG_VERSION: 1.19.5
|
||||
KUBERNETES_VERSION: "1.18.0"
|
||||
KIND_VERSION: "0.7.0"
|
||||
KIND_VERSION: "0.10.0"
|
||||
HELM_REGISTRY_URL: "https://stakater.github.io/stakater-charts"
|
||||
|
||||
jobs:
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
# Setting up helm binary
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v1
|
||||
uses: azure/setup-helm@v3.4
|
||||
|
||||
- name: Set up Go
|
||||
id: go
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2.3.0
|
||||
with:
|
||||
version: v1.33
|
||||
version: v1.45.2
|
||||
only-new-issues: false
|
||||
args: --timeout 10m
|
||||
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
- name: Generate Tag
|
||||
id: generate_tag
|
||||
uses: anothrNick/github-tag-action@1.26.0
|
||||
uses: anothrNick/github-tag-action@1.36.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.STAKATER_GITHUB_TOKEN }}
|
||||
WITH_V: true
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
# Generate tag for operator without "v"
|
||||
- name: Generate Operator Tag
|
||||
id: generate_operator_tag
|
||||
uses: anothrNick/github-tag-action@1.26.0
|
||||
uses: anothrNick/github-tag-action@1.36.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.STAKATER_GITHUB_TOKEN }}
|
||||
WITH_V: false
|
||||
@@ -132,7 +132,7 @@ jobs:
|
||||
- name: Helm Template
|
||||
run: |
|
||||
helm template reloader deployments/kubernetes/chart/reloader/ > deployments/kubernetes/reloader.yaml
|
||||
helm template reloader deployments/kubernetes/chart/reloader/ --output-dir deployments/kubernetes/manifests/ && mv deployments/kubernetes/manifests/reloader/templates/* deployments/kubernetes/manifests/ && rm -r deployments/kubernetes/manifests/reloader
|
||||
helm template reloader deployments/kubernetes/chart/reloader/ --output-dir deployments/kubernetes/manifests && mv deployments/kubernetes/manifests/reloader/templates/* deployments/kubernetes/manifests/ && rm -r deployments/kubernetes/manifests/reloader
|
||||
|
||||
# Publish helm chart
|
||||
- name: Publish Helm chart
|
||||
@@ -165,7 +165,7 @@ jobs:
|
||||
branch: ${{ github.ref }}
|
||||
|
||||
- name: Push Latest Tag
|
||||
uses: anothrNick/github-tag-action@1.26.0
|
||||
uses: anothrNick/github-tag-action@1.36.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.STAKATER_GITHUB_TOKEN }}
|
||||
WITH_V: true
|
||||
|
||||
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
- "v*"
|
||||
|
||||
env:
|
||||
GOLANG_VERSION: 1.17.2
|
||||
GOLANG_VERSION: 1.19.5
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -2,7 +2,7 @@ ARG BUILDER_IMAGE
|
||||
ARG BASE_IMAGE
|
||||
|
||||
# Build the manager binary
|
||||
FROM --platform=${BUILDPLATFORM} ${BUILDER_IMAGE:-golang:1.17.2} as builder
|
||||
FROM --platform=${BUILDPLATFORM} ${BUILDER_IMAGE:-golang:1.19.5} as builder
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
42
README.md
42
README.md
@@ -6,8 +6,6 @@
|
||||
[](https://github.com/stakater/reloader/releases/latest)
|
||||
[](https://hub.docker.com/r/stakater/reloader/)
|
||||
[](https://hub.docker.com/r/stakater/reloader/)
|
||||
[](https://microbadger.com/images/stakater/reloader)
|
||||
[](https://microbadger.com/images/stakater/reloader)
|
||||
[](LICENSE)
|
||||
[](http://stakater.com/?utm_source=Reloader&utm_medium=github)
|
||||
|
||||
@@ -33,7 +31,8 @@ metadata:
|
||||
annotations:
|
||||
reloader.stakater.com/auto: "true"
|
||||
spec:
|
||||
template: metadata:
|
||||
template:
|
||||
metadata:
|
||||
```
|
||||
|
||||
This will discover deploymentconfigs/deployments/daemonsets/statefulset/rollouts 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.
|
||||
@@ -88,7 +87,8 @@ metadata:
|
||||
annotations:
|
||||
configmap.reloader.stakater.com/reload: "foo-configmap"
|
||||
spec:
|
||||
template: metadata:
|
||||
template:
|
||||
metadata:
|
||||
```
|
||||
|
||||
Use comma separated list to define multiple configmaps.
|
||||
@@ -143,6 +143,7 @@ spec:
|
||||
- you may override the configmap annotation with the `--configmap-annotation` flag
|
||||
- you may override the secret annotation with the `--secret-annotation` flag
|
||||
- you may want to prevent watching certain namespaces with the `--namespaces-to-ignore` flag
|
||||
- you may want to watch only a set of namespaces with certain labels by using the `--namespace-selector` flag
|
||||
- you may want to prevent watching certain resources with the `--resources-to-ignore` flag
|
||||
- you can configure logging in JSON format with the `--log-format=json` option
|
||||
- you can configure the "reload strategy" with the `--reload-strategy=<strategy-name>` option (details below)
|
||||
@@ -182,6 +183,25 @@ Reloader can be configured to ignore the resources `secrets` and `configmaps` by
|
||||
|
||||
`Note`: At one time only one of these resource can be ignored, trying to do it will cause error in Reloader. Workaround for ignoring both resources is by scaling down the reloader pods to `0`.
|
||||
|
||||
Reloader can be configured to watch only namespaces labeled with (one or more) labels of your choosing by using the `--namespace-selector` parameter, for example:
|
||||
```
|
||||
--namespace-selector=reloder:enabled,test:true
|
||||
```
|
||||
|
||||
Only namespaces labeled like the following namespace YAML will be watched:
|
||||
```yaml
|
||||
kind: Namespace
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
...
|
||||
labels:
|
||||
reloder: enabled
|
||||
test: true
|
||||
...
|
||||
```
|
||||
If you want to select namespace only by the key of the label use ```*``` as the value.
|
||||
For example, for ```--namespace-selector=select-this:*``` all namespaces with label-key "select-this" will be selected regardless of the labels value
|
||||
|
||||
### Vanilla kustomize
|
||||
|
||||
You can also apply the vanilla manifests by running the following command
|
||||
@@ -233,6 +253,12 @@ Reloader can be configured to ignore the resources `secrets` and `configmaps` by
|
||||
|
||||
`Note`: At one time only one of these resource can be ignored, trying to do it will cause error in helm template compilation.
|
||||
|
||||
Reloader can be configured to watch only namespaces labeled with (one or more) labels of your choosing by using the `namespaceSelector` parameter
|
||||
|
||||
| Parameter | Description | Type |
|
||||
| ---------------- | -------------------------------------------------------------- | ------- |
|
||||
| namespaceSelector | list of comma separated key:value namespace | string |
|
||||
|
||||
You can also set the log format of Reloader to json by setting `logFormat` to `json` in values.yaml and apply the chart
|
||||
|
||||
You can enable to scrape Reloader's Prometheus metrics by setting `serviceMonitor.enabled` or `podMonitor.enabled` to `true` in values.yaml file. Service monitor will be removed in future releases of reloader in favour of Pod monitor.
|
||||
@@ -245,6 +271,14 @@ You can enable to scrape Reloader's Prometheus metrics by setting `serviceMonito
|
||||
| isArgoRollouts | Enable Argo Rollouts. Valid value are either `true` or `false` | boolean |
|
||||
| reloadOnCreate | Enable reload on create events. Valid value are either `true` or `false` | boolean |
|
||||
|
||||
**ReloadOnCreate** reloadOnCreate controls how Reloader handles secrets being added to the cache for the first time. If reloadOnCreate is set to true:
|
||||
* Configmaps/secrets being added to the cache will cause Reloader to perform a rolling update of the associated workload.
|
||||
* When applications are deployed for the first time, Reloader will perform a rolling update of the associated workload.
|
||||
* If you are running Reloader in HA mode all workloads will have a rolling update performed when a new leader is elected.
|
||||
|
||||
If ReloadOnCreate is set to false:
|
||||
* Updates to configMaps/Secrets that occur while there is no leader will not be picked up by the new leader until a subsequent update of the configmap/secret occurs. In the worst case the window in which there can be no leader is 15s as this is the LeaseDuration.
|
||||
|
||||
## Help
|
||||
|
||||
### Documentation
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
apiVersion: v1
|
||||
name: reloader
|
||||
description: Reloader chart that runs on kubernetes
|
||||
version: v0.0.108
|
||||
appVersion: v0.0.108
|
||||
version: v1.0.2
|
||||
appVersion: v1.0.2
|
||||
keywords:
|
||||
- Reloader
|
||||
- kubernetes
|
||||
@@ -16,16 +16,6 @@ maintainers:
|
||||
- name: Stakater
|
||||
email: hello@stakater.com
|
||||
- name: rasheedamir
|
||||
email: rasheed@aurorasolutions.io
|
||||
- name: waseem-h
|
||||
email: waseemhassan@stakater.com
|
||||
email: rasheed@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
|
||||
- name: ahmedwaleedmalik
|
||||
email: waleed@stakater.com
|
||||
|
||||
@@ -28,6 +28,23 @@ heritage: {{ .Release.Service | quote }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create pod anti affinity labels
|
||||
*/}}
|
||||
{{- define "reloader-podAntiAffinity" -}}
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- {{ template "reloader-fullname" . }}
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
@@ -45,4 +62,4 @@ Create the annotations to support helm3
|
||||
{{- define "reloader-helm3.annotations" -}}
|
||||
meta.helm.sh/release-namespace: {{ .Release.Namespace | quote }}
|
||||
meta.helm.sh/release-name: {{ .Release.Name | quote }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -17,7 +17,7 @@ metadata:
|
||||
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
|
||||
{{- end }}
|
||||
name: {{ template "reloader-fullname" . }}-role
|
||||
namespace: {{ .Release.Namespace }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
@@ -32,6 +32,14 @@ rules:
|
||||
- list
|
||||
- get
|
||||
- watch
|
||||
{{- if .Values.reloader.namespaceSelector }}
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- namespaces
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
{{- if and (.Capabilities.APIVersions.Has "apps.openshift.io/v1") (.Values.reloader.isOpenshift) }}
|
||||
- apiGroups:
|
||||
- "apps.openshift.io"
|
||||
@@ -77,4 +85,21 @@ rules:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
{{- if .Values.reloader.enableHA }}
|
||||
- apiGroups:
|
||||
- "coordination.k8s.io"
|
||||
resources:
|
||||
- leases
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- update
|
||||
{{- end}}
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
{{- end }}
|
||||
|
||||
@@ -17,7 +17,7 @@ metadata:
|
||||
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
|
||||
{{- end }}
|
||||
name: {{ template "reloader-fullname" . }}-role-binding
|
||||
namespace: {{ .Release.Namespace }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
@@ -25,5 +25,5 @@ roleRef:
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ template "reloader-serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
{{- end }}
|
||||
|
||||
@@ -15,9 +15,13 @@ metadata:
|
||||
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
|
||||
{{- end }}
|
||||
name: {{ template "reloader-fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
spec:
|
||||
{{- if not (.Values.reloader.enableHA) }}
|
||||
replicas: 1
|
||||
{{- else }}
|
||||
replicas: {{ .Values.reloader.deployment.replicas }}
|
||||
{{- end}}
|
||||
revisionHistoryLimit: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
@@ -41,13 +45,20 @@ spec:
|
||||
{{ toYaml .Values.reloader.matchLabels | indent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.reloader.deployment.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.deployment.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml .Values.reloader.deployment.nodeSelector | indent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.deployment.affinity }}
|
||||
{{- if or (.Values.reloader.deployment.affinity) (.Values.reloader.enableHA) }}
|
||||
affinity:
|
||||
{{- if .Values.reloader.deployment.affinity }}
|
||||
{{ toYaml .Values.reloader.deployment.affinity | indent 8 }}
|
||||
{{- end}}
|
||||
{{ include "reloader-podAntiAffinity" . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.deployment.tolerations }}
|
||||
tolerations:
|
||||
@@ -60,7 +71,7 @@ spec:
|
||||
- image: "{{ .Values.reloader.deployment.image.name }}:{{ .Values.reloader.deployment.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.reloader.deployment.image.pullPolicy }}
|
||||
name: {{ template "reloader-fullname" . }}
|
||||
{{- if or (.Values.reloader.deployment.env.open) (.Values.reloader.deployment.env.secret) (.Values.reloader.deployment.env.field) (eq .Values.reloader.watchGlobally false) }}
|
||||
{{- if or (.Values.reloader.deployment.env.open) (.Values.reloader.deployment.env.secret) (.Values.reloader.deployment.env.field) (.Values.reloader.deployment.env.existing) (eq .Values.reloader.watchGlobally false) (.Values.reloader.enableHA)}}
|
||||
env:
|
||||
{{- range $name, $value := .Values.reloader.deployment.env.open }}
|
||||
{{- if not (empty $value) }}
|
||||
@@ -78,6 +89,17 @@ spec:
|
||||
key: {{ $name | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $secret, $values := .Values.reloader.deployment.env.existing }}
|
||||
{{- range $name, $key := $values }}
|
||||
{{- if not ( empty $name) }}
|
||||
- name: {{ $name | quote }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ $secret | quote }}
|
||||
key: {{ $key | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $name, $value := .Values.reloader.deployment.env.field }}
|
||||
{{- if not ( empty $value) }}
|
||||
- name: {{ $name | quote }}
|
||||
@@ -92,14 +114,26 @@ spec:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.enableHA }}
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9091
|
||||
- name: metrics
|
||||
containerPort: 9090
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /metrics
|
||||
path: /live
|
||||
port: http
|
||||
timeoutSeconds: {{ .Values.reloader.deployment.livenessProbe.timeoutSeconds | default "5" }}
|
||||
failureThreshold: {{ .Values.reloader.deployment.livenessProbe.failureThreshold | default "5" }}
|
||||
@@ -108,7 +142,7 @@ spec:
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /metrics
|
||||
port: http
|
||||
port: metrics
|
||||
timeoutSeconds: {{ .Values.reloader.deployment.readinessProbe.timeoutSeconds | default "5" }}
|
||||
failureThreshold: {{ .Values.reloader.deployment.readinessProbe.failureThreshold | default "5" }}
|
||||
periodSeconds: {{ .Values.reloader.deployment.readinessProbe.periodSeconds | default "10" }}
|
||||
@@ -123,7 +157,7 @@ spec:
|
||||
- mountPath: /tmp/
|
||||
name: tmp-volume
|
||||
{{- end }}
|
||||
{{- if or (.Values.reloader.logFormat) (.Values.reloader.ignoreSecrets) (.Values.reloader.ignoreNamespaces) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (ne .Values.reloader.reloadStrategy "default")}}
|
||||
{{- if or (.Values.reloader.logFormat) (.Values.reloader.ignoreSecrets) (.Values.reloader.ignoreNamespaces) (.Values.reloader.namespaceSelector) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (ne .Values.reloader.reloadStrategy "default") (.Values.reloader.enableHA)}}
|
||||
args:
|
||||
{{- if .Values.reloader.logFormat }}
|
||||
- "--log-format={{ .Values.reloader.logFormat }}"
|
||||
@@ -137,7 +171,9 @@ spec:
|
||||
{{- if .Values.reloader.ignoreNamespaces }}
|
||||
- "--namespaces-to-ignore={{ .Values.reloader.ignoreNamespaces }}"
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.reloader.namespaceSelector }}
|
||||
- "--namespace-selector={{ .Values.reloader.namespaceSelector }}"
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.custom_annotations }}
|
||||
{{- if .Values.reloader.custom_annotations.configmap }}
|
||||
- "--configmap-annotation"
|
||||
@@ -169,6 +205,9 @@ spec:
|
||||
{{- if ne .Values.reloader.reloadStrategy "default" }}
|
||||
- "--reload-strategy={{ .Values.reloader.reloadStrategy }}"
|
||||
{{- end }}
|
||||
{{- if or (gt .Values.reloader.deployment.replicas 1.0) (.Values.reloader.enableHA) }}
|
||||
- "--enable-ha=true"
|
||||
{{- end}}
|
||||
{{- end }}
|
||||
{{- if .Values.reloader.deployment.resources }}
|
||||
resources:
|
||||
@@ -178,6 +217,9 @@ spec:
|
||||
securityContext: {{ toYaml .Values.reloader.deployment.securityContext | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ template "reloader-serviceAccountName" . }}
|
||||
{{- if hasKey .Values.reloader.deployment "automountServiceAccountToken" }}
|
||||
automountServiceAccountToken: {{ .Values.reloader.deployment.automountServiceAccountToken }}
|
||||
{{- end }}
|
||||
{{- if eq .Values.reloader.readOnlyRootFileSystem true }}
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{{- if .Values.reloader.podDisruptionBudget.enabled }}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ template "reloader-fullname" . }}
|
||||
spec:
|
||||
minAvailable: {{ .Values.reloader.podDisruptionBudget.minAvailable }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "reloader-fullname" . }}
|
||||
{{- end }}
|
||||
@@ -1,4 +1,4 @@
|
||||
{{- if and ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) ( .Values.reloader.podMonitor.enabled ) }}
|
||||
{{- if ( .Values.reloader.podMonitor.enabled ) }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: PodMonitor
|
||||
metadata:
|
||||
|
||||
@@ -17,7 +17,7 @@ metadata:
|
||||
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
|
||||
{{- end }}
|
||||
name: {{ template "reloader-fullname" . }}-role
|
||||
namespace: {{ .Release.Namespace }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
@@ -77,4 +77,21 @@ rules:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
{{- if .Values.reloader.enableHA }}
|
||||
- apiGroups:
|
||||
- "coordination.k8s.io"
|
||||
resources:
|
||||
- leases
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- update
|
||||
{{- end}}
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
{{- end }}
|
||||
|
||||
@@ -17,7 +17,7 @@ metadata:
|
||||
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
|
||||
{{- end }}
|
||||
name: {{ template "reloader-fullname" . }}-role-binding
|
||||
namespace: {{ .Release.Namespace }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
@@ -25,5 +25,5 @@ roleRef:
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ template "reloader-serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
{{- end }}
|
||||
|
||||
21
deployments/kubernetes/chart/reloader/templates/secret.yaml
Normal file
21
deployments/kubernetes/chart/reloader/templates/secret.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
{{- if .Values.reloader.deployment.env.secret -}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "reloader-fullname" . }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
type: Opaque
|
||||
data:
|
||||
{{ if .Values.reloader.deployment.env.secret.ALERT_ON_RELOAD -}}
|
||||
ALERT_ON_RELOAD: {{ .Values.reloader.deployment.env.secret.ALERT_ON_RELOAD | b64enc | quote }}
|
||||
{{ end }}
|
||||
{{- if .Values.reloader.deployment.env.secret.ALERT_SINK -}}
|
||||
ALERT_SINK: {{ .Values.reloader.deployment.env.secret.ALERT_SINK | b64enc | quote }}
|
||||
{{ end }}
|
||||
{{- if .Values.reloader.deployment.env.secret.ALERT_WEBHOOK_URL -}}
|
||||
ALERT_WEBHOOK_URL: {{ .Values.reloader.deployment.env.secret.ALERT_WEBHOOK_URL | b64enc | quote }}
|
||||
{{ end }}
|
||||
{{- if .Values.reloader.deployment.env.secret.ALERT_ADDITIONAL_INFO -}}
|
||||
ALERT_ADDITIONAL_INFO: {{ .Values.reloader.deployment.env.secret.ALERT_ADDITIONAL_INFO | b64enc | quote }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -13,6 +13,7 @@ metadata:
|
||||
{{ toYaml .Values.reloader.service.labels | indent 4 }}
|
||||
{{- end }}
|
||||
name: {{ template "reloader-fullname" . }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
spec:
|
||||
selector:
|
||||
{{- if .Values.reloader.deployment.labels }}
|
||||
|
||||
@@ -4,6 +4,9 @@ kind: ServiceAccount
|
||||
{{- if .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets: {{ toYaml .Values.global.imagePullSecrets | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- if hasKey .Values.reloader.serviceAccount "automountServiceAccountToken" }}
|
||||
automountServiceAccountToken: {{ .Values.reloader.serviceAccount.automountServiceAccountToken }}
|
||||
{{- end }}
|
||||
metadata:
|
||||
annotations:
|
||||
{{ include "reloader-helm3.annotations" . | indent 4 }}
|
||||
@@ -19,5 +22,5 @@ metadata:
|
||||
{{ toYaml .Values.reloader.matchLabels | indent 4 }}
|
||||
{{- end }}
|
||||
name: {{ template "reloader-serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
namespace: {{ .Values.namespace | default .Release.Namespace }}
|
||||
{{- end }}
|
||||
|
||||
@@ -16,14 +16,18 @@ reloader:
|
||||
reloadOnCreate: false
|
||||
reloadStrategy: default # Set to default, env-vars or annotations
|
||||
ignoreNamespaces: "" # Comma separated list of namespaces to ignore
|
||||
namespaceSelector: "" # Comma separated list of 'key:value' labels for namespaces selection
|
||||
logFormat: "" #json
|
||||
watchGlobally: true
|
||||
# Set to true to enable leadership election allowing you to run multiple replicas
|
||||
enableHA: false
|
||||
# Set to true if you have a pod security policy that enforces readOnlyRootFilesystem
|
||||
readOnlyRootFileSystem: false
|
||||
legacy:
|
||||
rbac: false
|
||||
matchLabels: {}
|
||||
deployment:
|
||||
# If you wish to run multiple replicas set reloader.enableHA = true
|
||||
replicas: 1
|
||||
nodeSelector:
|
||||
# cloud.google.com/gke-nodepool: default-pool
|
||||
@@ -62,10 +66,10 @@ reloader:
|
||||
labels:
|
||||
provider: stakater
|
||||
group: com.stakater.platform
|
||||
version: v0.0.108
|
||||
version: v1.0.2
|
||||
image:
|
||||
name: stakater/reloader
|
||||
tag: v0.0.108
|
||||
tag: v1.0.2
|
||||
pullPolicy: IfNotPresent
|
||||
# Support for extra environment variables.
|
||||
env:
|
||||
@@ -73,8 +77,21 @@ reloader:
|
||||
open:
|
||||
# secret supports Key value pair as environment variables. It gets the values based on keys from default reloader secret if any.
|
||||
secret:
|
||||
# ALERT_ON_RELOAD: <"true"|"false">
|
||||
# ALERT_SINK: <"slack"> # By default it will be a raw text based webhook
|
||||
# ALERT_WEBHOOK_URL: <"webhook_url">
|
||||
# ALERT_ADDITIONAL_INFO: <"Additional Info like Cluster Name if needed">
|
||||
# field supports Key value pair as environment variables. It gets the values from other fields of pod.
|
||||
field:
|
||||
# existing secret, you can specify multiple existing secrets, for each
|
||||
# specify the env var name followed by the key in existing secret that
|
||||
# will be used to populate the env var
|
||||
existing:
|
||||
# existing_secret_name:
|
||||
# ALERT_ON_RELOAD: alert_on_reload_key
|
||||
# ALERT_SINK: alert_sink_key
|
||||
# ALERT_WEBHOOK_URL: alert_webhook_key
|
||||
# ALERT_ADDITIONAL_INFO: alert_additional_info_key
|
||||
|
||||
# Liveness and readiness probe timeout values.
|
||||
livenessProbe: {}
|
||||
@@ -101,6 +118,8 @@ reloader:
|
||||
pod:
|
||||
annotations: {}
|
||||
priorityClassName: ""
|
||||
# imagePullSecrets:
|
||||
# - name: myregistrykey
|
||||
|
||||
service: {}
|
||||
# labels: {}
|
||||
@@ -118,7 +137,7 @@ reloader:
|
||||
annotations: {}
|
||||
# The name of the ServiceAccount to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name:
|
||||
name:
|
||||
# Optional flags to pass to the Reloader entrypoint
|
||||
# Example:
|
||||
# custom_annotations:
|
||||
@@ -149,3 +168,8 @@ reloader:
|
||||
# labels:
|
||||
# Set timeout for scrape
|
||||
# timeout: 10s
|
||||
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
# Set the minimum available replicas
|
||||
# minAvailable: 1
|
||||
|
||||
@@ -9,7 +9,7 @@ metadata:
|
||||
meta.helm.sh/release-name: "reloader"
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
@@ -46,3 +46,10 @@ rules:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
|
||||
@@ -9,7 +9,7 @@ metadata:
|
||||
meta.helm.sh/release-name: "reloader"
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
|
||||
@@ -8,13 +8,13 @@ metadata:
|
||||
meta.helm.sh/release-name: "reloader"
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
group: com.stakater.platform
|
||||
provider: stakater
|
||||
version: v0.0.108
|
||||
version: v1.0.2
|
||||
name: reloader-reloader
|
||||
namespace: default
|
||||
spec:
|
||||
@@ -28,25 +28,27 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
group: com.stakater.platform
|
||||
provider: stakater
|
||||
version: v0.0.108
|
||||
version: v1.0.2
|
||||
spec:
|
||||
containers:
|
||||
- image: "stakater/reloader:v0.0.108"
|
||||
- image: "stakater/reloader:v1.0.2"
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: reloader-reloader
|
||||
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9091
|
||||
- name: metrics
|
||||
containerPort: 9090
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /metrics
|
||||
path: /live
|
||||
port: http
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 5
|
||||
@@ -55,7 +57,7 @@ spec:
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /metrics
|
||||
port: http
|
||||
port: metrics
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 5
|
||||
periodSeconds: 10
|
||||
|
||||
@@ -8,7 +8,7 @@ metadata:
|
||||
meta.helm.sh/release-name: "reloader"
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
|
||||
@@ -8,7 +8,7 @@ metadata:
|
||||
meta.helm.sh/release-name: "reloader"
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
@@ -25,7 +25,7 @@ metadata:
|
||||
meta.helm.sh/release-name: "reloader"
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
@@ -62,6 +62,13 @@ rules:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
---
|
||||
# Source: reloader/templates/clusterrolebinding.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -73,7 +80,7 @@ metadata:
|
||||
meta.helm.sh/release-name: "reloader"
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
@@ -97,13 +104,13 @@ metadata:
|
||||
meta.helm.sh/release-name: "reloader"
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
group: com.stakater.platform
|
||||
provider: stakater
|
||||
version: v0.0.108
|
||||
version: v1.0.2
|
||||
name: reloader-reloader
|
||||
namespace: default
|
||||
spec:
|
||||
@@ -117,25 +124,27 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
app: reloader-reloader
|
||||
chart: "reloader-v0.0.108"
|
||||
chart: "reloader-v1.0.2"
|
||||
release: "reloader"
|
||||
heritage: "Helm"
|
||||
app.kubernetes.io/managed-by: "Helm"
|
||||
group: com.stakater.platform
|
||||
provider: stakater
|
||||
version: v0.0.108
|
||||
version: v1.0.2
|
||||
spec:
|
||||
containers:
|
||||
- image: "stakater/reloader:v0.0.108"
|
||||
- image: "stakater/reloader:v1.0.2"
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: reloader-reloader
|
||||
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9091
|
||||
- name: metrics
|
||||
containerPort: 9090
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /metrics
|
||||
path: /live
|
||||
port: http
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 5
|
||||
@@ -144,7 +153,7 @@ spec:
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /metrics
|
||||
port: http
|
||||
port: metrics
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 5
|
||||
periodSeconds: 10
|
||||
|
||||
12
docs/Alerting.md
Normal file
12
docs/Alerting.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Alerting on Reload
|
||||
Reloader can alert when it triggers a rolling upgrade on Deployments or StatefulSets. Webhook notification alert would be sent to the configured webhook server with all the required information
|
||||
|
||||
#### Enabling the feature
|
||||
In-order to enable this feature, you need to update the reloader.env.secret section of values.yaml providing the information needed for alert.
|
||||
<pre> ALERT_ON_RELOAD: [ true/false ] Default: false
|
||||
ALERT_SINK: [ slack/webhook ] Default: webhook
|
||||
ALERT_WEBHOOK_URL: Required if ALERT_ON_RELOAD is true
|
||||
ALERT_ADDITIONAL_INFO: Any additional information to be added to alert
|
||||
|
||||
#### Slack incoming-webhook creation docs
|
||||
https://api.slack.com/messaging/webhooks
|
||||
149
go.mod
149
go.mod
@@ -1,97 +1,100 @@
|
||||
module github.com/stakater/Reloader
|
||||
|
||||
go 1.17
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/argoproj/argo-rollouts v1.0.2
|
||||
github.com/argoproj/argo-rollouts v1.4.0
|
||||
github.com/openshift/api v0.0.0-20210527122704-efd9d5958e01
|
||||
github.com/openshift/client-go v0.0.0-20210521082421-73d9475a9142
|
||||
github.com/prometheus/client_golang v1.10.0
|
||||
github.com/sirupsen/logrus v1.7.0
|
||||
github.com/spf13/cobra v1.1.3
|
||||
k8s.io/api v0.21.2
|
||||
k8s.io/apimachinery v0.21.2
|
||||
k8s.io/client-go v0.21.2
|
||||
github.com/parnurzeal/gorequest v0.2.16
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
k8s.io/api v0.26.1
|
||||
k8s.io/apimachinery v0.26.1
|
||||
k8s.io/client-go v0.26.1
|
||||
k8s.io/kubectl v0.26.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible // indirect
|
||||
github.com/go-logr/logr v0.4.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.3 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.3 // indirect
|
||||
github.com/go-openapi/spec v0.19.3 // indirect
|
||||
github.com/go-openapi/swag v0.19.5 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.4.3 // indirect
|
||||
github.com/google/go-cmp v0.5.4 // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/googleapis/gnostic v0.4.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/imdario/mergo v0.3.11 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.10 // indirect
|
||||
github.com/mailru/easyjson v0.7.0 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/gnostic v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/onsi/ginkgo v1.15.1 // indirect
|
||||
github.com/onsi/gomega v1.11.0 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.21.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.7.2 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
|
||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect
|
||||
golang.org/x/text v0.3.4 // indirect
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
|
||||
google.golang.org/appengine v1.6.6 // indirect
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
golang.org/x/net v0.4.0 // indirect
|
||||
golang.org/x/oauth2 v0.3.0 // indirect
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/term v0.3.0 // indirect
|
||||
golang.org/x/text v0.5.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.8.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20210216185858-15cd8face8d6 // indirect
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog/v2 v2.80.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
|
||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
|
||||
moul.io/http2curl v1.0.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
// Replacements for argo-rollouts
|
||||
replace (
|
||||
github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127
|
||||
github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
k8s.io/api => k8s.io/api v0.20.4
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.20.4
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.21.0-alpha.0
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.20.4
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.20.4
|
||||
k8s.io/client-go => k8s.io/client-go v0.20.4
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.20.4
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.20.4
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.20.5-rc.0
|
||||
k8s.io/component-base => k8s.io/component-base v0.20.4
|
||||
k8s.io/component-helpers => k8s.io/component-helpers v0.20.4
|
||||
k8s.io/controller-manager => k8s.io/controller-manager v0.20.4
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.20.5-rc.0
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.20.4
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.20.4
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.20.4
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.20.4
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.20.4
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.20.4
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.20.4
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.20.4
|
||||
k8s.io/metrics => k8s.io/metrics v0.20.4
|
||||
k8s.io/mount-utils => k8s.io/mount-utils v0.20.5-rc.0
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.20.4
|
||||
k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.20.4
|
||||
k8s.io/sample-controller => k8s.io/sample-controller v0.20.4
|
||||
k8s.io/api v0.0.0 => k8s.io/api v0.24.2
|
||||
k8s.io/apiextensions-apiserver v0.0.0 => k8s.io/apiextensions-apiserver v0.24.2
|
||||
k8s.io/apimachinery v0.0.0 => k8s.io/apimachinery v0.21.0-alpha.0
|
||||
k8s.io/apiserver v0.0.0 => k8s.io/apiserver v0.24.2
|
||||
k8s.io/cli-runtime v0.0.0 => k8s.io/cli-runtime v0.24.2
|
||||
k8s.io/client-go v0.0.0 => k8s.io/client-go v0.24.2
|
||||
k8s.io/cloud-provider v0.0.0 => k8s.io/cloud-provider v0.24.2
|
||||
k8s.io/cluster-bootstrap v0.0.0 => k8s.io/cluster-bootstrap v0.24.2
|
||||
k8s.io/code-generator v0.0.0 => k8s.io/code-generator v0.20.5-rc.0
|
||||
k8s.io/component-base v0.0.0 => k8s.io/component-base v0.24.2
|
||||
k8s.io/component-helpers v0.0.0 => k8s.io/component-helpers v0.24.2
|
||||
k8s.io/controller-manager v0.0.0 => k8s.io/controller-manager v0.24.2
|
||||
k8s.io/cri-api v0.0.0 => k8s.io/cri-api v0.20.5-rc.0
|
||||
k8s.io/csi-translation-lib v0.0.0 => k8s.io/csi-translation-lib v0.24.2
|
||||
k8s.io/kube-aggregator v0.0.0 => k8s.io/kube-aggregator v0.24.2
|
||||
k8s.io/kube-controller-manager v0.0.0 => k8s.io/kube-controller-manager v0.24.2
|
||||
k8s.io/kube-proxy v0.0.0 => k8s.io/kube-proxy v0.24.2
|
||||
k8s.io/kube-scheduler v0.0.0 => k8s.io/kube-scheduler v0.24.2
|
||||
k8s.io/kubectl v0.0.0 => k8s.io/kubectl v0.24.2
|
||||
k8s.io/kubelet v0.0.0 => k8s.io/kubelet v0.24.2
|
||||
k8s.io/legacy-cloud-providers v0.0.0 => k8s.io/legacy-cloud-providers v0.24.2
|
||||
k8s.io/metrics v0.0.0 => k8s.io/metrics v0.24.2
|
||||
k8s.io/mount-utils v0.0.0 => k8s.io/mount-utils v0.20.5-rc.0
|
||||
k8s.io/sample-apiserver v0.0.0 => k8s.io/sample-apiserver v0.24.2
|
||||
k8s.io/sample-cli-plugin v0.0.0 => k8s.io/sample-cli-plugin v0.24.2
|
||||
k8s.io/sample-controller v0.0.0 => k8s.io/sample-controller v0.24.2
|
||||
)
|
||||
|
||||
94
internal/pkg/alerts/alert.go
Normal file
94
internal/pkg/alerts/alert.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package alert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/parnurzeal/gorequest"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// function to send alert msg to webhook service
|
||||
func SendWebhookAlert(msg string) {
|
||||
webhook_url, ok := os.LookupEnv("ALERT_WEBHOOK_URL")
|
||||
if !ok {
|
||||
logrus.Error("ALERT_WEBHOOK_URL env variable not provided")
|
||||
return
|
||||
}
|
||||
webhook_url = strings.TrimSpace(webhook_url)
|
||||
alert_sink := os.Getenv("ALERT_SINK")
|
||||
alert_sink = strings.ToLower(strings.TrimSpace(alert_sink))
|
||||
|
||||
// Provision to add Proxy to reach webhook server if required
|
||||
webhook_proxy := os.Getenv("ALERT_WEBHOOK_PROXY")
|
||||
webhook_proxy = strings.TrimSpace(webhook_proxy)
|
||||
|
||||
// Provision to add Additional information in the alert. e.g ClusterName
|
||||
alert_additional_info, ok := os.LookupEnv("ALERT_ADDITIONAL_INFO")
|
||||
if ok {
|
||||
alert_additional_info = strings.TrimSpace(alert_additional_info)
|
||||
msg = fmt.Sprintf("%s : %s", alert_additional_info, msg)
|
||||
}
|
||||
|
||||
if alert_sink == "slack" {
|
||||
sendSlackAlert(webhook_url, webhook_proxy, msg)
|
||||
} else {
|
||||
msg = strings.Replace(msg, "*", "", -1)
|
||||
sendRawWebhookAlert(webhook_url, webhook_proxy, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// function to handle server redirection
|
||||
func redirectPolicy(req gorequest.Request, via []gorequest.Request) error {
|
||||
return fmt.Errorf("incorrect token (redirection)")
|
||||
}
|
||||
|
||||
// function to send alert to slack
|
||||
func sendSlackAlert(webhookUrl string, proxy string, msg string) []error {
|
||||
attachment := Attachment{
|
||||
Text: msg,
|
||||
Color: "good",
|
||||
AuthorName: "Reloader",
|
||||
}
|
||||
|
||||
payload := WebhookMessage{
|
||||
Attachments: []Attachment{attachment},
|
||||
}
|
||||
|
||||
request := gorequest.New().Proxy(proxy)
|
||||
resp, _, err := request.
|
||||
Post(webhookUrl).
|
||||
RedirectPolicy(redirectPolicy).
|
||||
Send(payload).
|
||||
End()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode >= 400 {
|
||||
return []error{fmt.Errorf("error sending msg. status: %v", resp.Status)}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// function to send alert to webhook service as text
|
||||
func sendRawWebhookAlert(webhookUrl string, proxy string, msg string) []error {
|
||||
request := gorequest.New().Proxy(proxy)
|
||||
resp, _, err := request.
|
||||
Post(webhookUrl).
|
||||
Type("text").
|
||||
RedirectPolicy(redirectPolicy).
|
||||
Send(msg).
|
||||
End()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode >= 400 {
|
||||
return []error{fmt.Errorf("error sending msg. status: %v", resp.Status)}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
61
internal/pkg/alerts/slack_alert.go
Normal file
61
internal/pkg/alerts/slack_alert.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package alert
|
||||
|
||||
type WebhookMessage struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
IconEmoji string `json:"icon_emoji,omitempty"`
|
||||
IconURL string `json:"icon_url,omitempty"`
|
||||
Channel string `json:"channel,omitempty"`
|
||||
ThreadTimestamp string `json:"thread_ts,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
Attachments []Attachment `json:"attachments,omitempty"`
|
||||
Parse string `json:"parse,omitempty"`
|
||||
ResponseType string `json:"response_type,omitempty"`
|
||||
ReplaceOriginal bool `json:"replace_original,omitempty"`
|
||||
DeleteOriginal bool `json:"delete_original,omitempty"`
|
||||
ReplyBroadcast bool `json:"reply_broadcast,omitempty"`
|
||||
}
|
||||
|
||||
type Attachment struct {
|
||||
Color string `json:"color,omitempty"`
|
||||
Fallback string `json:"fallback,omitempty"`
|
||||
|
||||
CallbackID string `json:"callback_id,omitempty"`
|
||||
ID int `json:"id,omitempty"`
|
||||
|
||||
AuthorID string `json:"author_id,omitempty"`
|
||||
AuthorName string `json:"author_name,omitempty"`
|
||||
AuthorSubname string `json:"author_subname,omitempty"`
|
||||
AuthorLink string `json:"author_link,omitempty"`
|
||||
AuthorIcon string `json:"author_icon,omitempty"`
|
||||
|
||||
Title string `json:"title,omitempty"`
|
||||
TitleLink string `json:"title_link,omitempty"`
|
||||
Pretext string `json:"pretext,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
|
||||
ImageURL string `json:"image_url,omitempty"`
|
||||
ThumbURL string `json:"thumb_url,omitempty"`
|
||||
|
||||
ServiceName string `json:"service_name,omitempty"`
|
||||
ServiceIcon string `json:"service_icon,omitempty"`
|
||||
FromURL string `json:"from_url,omitempty"`
|
||||
OriginalURL string `json:"original_url,omitempty"`
|
||||
|
||||
MarkdownIn []string `json:"mrkdwn_in,omitempty"`
|
||||
|
||||
Footer string `json:"footer,omitempty"`
|
||||
FooterIcon string `json:"footer_icon,omitempty"`
|
||||
}
|
||||
|
||||
type Field struct {
|
||||
Title string `json:"title"`
|
||||
Value string `json:"value"`
|
||||
Short bool `json:"short"`
|
||||
}
|
||||
|
||||
type Action struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text"`
|
||||
Url string `json:"url"`
|
||||
Style string `json:"style"`
|
||||
}
|
||||
@@ -2,39 +2,40 @@ package callbacks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
"github.com/stakater/Reloader/pkg/kube"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
argorolloutv1alpha1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
|
||||
openshiftv1 "github.com/openshift/api/apps/v1"
|
||||
)
|
||||
|
||||
//ItemsFunc is a generic function to return a specific resource array in given namespace
|
||||
type ItemsFunc func(kube.Clients, string) []interface{}
|
||||
// ItemsFunc is a generic function to return a specific resource array in given namespace
|
||||
type ItemsFunc func(kube.Clients, string) []runtime.Object
|
||||
|
||||
//ContainersFunc is a generic func to return containers
|
||||
type ContainersFunc func(interface{}) []v1.Container
|
||||
// ContainersFunc is a generic func to return containers
|
||||
type ContainersFunc func(runtime.Object) []v1.Container
|
||||
|
||||
//InitContainersFunc is a generic func to return containers
|
||||
type InitContainersFunc func(interface{}) []v1.Container
|
||||
// InitContainersFunc is a generic func to return containers
|
||||
type InitContainersFunc func(runtime.Object) []v1.Container
|
||||
|
||||
//VolumesFunc is a generic func to return volumes
|
||||
type VolumesFunc func(interface{}) []v1.Volume
|
||||
// VolumesFunc is a generic func to return volumes
|
||||
type VolumesFunc func(runtime.Object) []v1.Volume
|
||||
|
||||
//UpdateFunc performs the resource update
|
||||
type UpdateFunc func(kube.Clients, string, interface{}) error
|
||||
// UpdateFunc performs the resource update
|
||||
type UpdateFunc func(kube.Clients, string, runtime.Object) error
|
||||
|
||||
//AnnotationsFunc is a generic func to return annotations
|
||||
type AnnotationsFunc func(interface{}) map[string]string
|
||||
// AnnotationsFunc is a generic func to return annotations
|
||||
type AnnotationsFunc func(runtime.Object) map[string]string
|
||||
|
||||
//PodAnnotationsFunc is a generic func to return annotations
|
||||
type PodAnnotationsFunc func(interface{}) map[string]string
|
||||
// PodAnnotationsFunc is a generic func to return annotations
|
||||
type PodAnnotationsFunc func(runtime.Object) map[string]string
|
||||
|
||||
//RollingUpgradeFuncs contains generic functions to perform rolling upgrade
|
||||
// RollingUpgradeFuncs contains generic functions to perform rolling upgrade
|
||||
type RollingUpgradeFuncs struct {
|
||||
ItemsFunc ItemsFunc
|
||||
AnnotationsFunc AnnotationsFunc
|
||||
@@ -47,250 +48,260 @@ type RollingUpgradeFuncs struct {
|
||||
}
|
||||
|
||||
// GetDeploymentItems returns the deployments in given namespace
|
||||
func GetDeploymentItems(clients kube.Clients, namespace string) []interface{} {
|
||||
func GetDeploymentItems(clients kube.Clients, namespace string) []runtime.Object {
|
||||
deployments, err := clients.KubernetesClient.AppsV1().Deployments(namespace).List(context.TODO(), meta_v1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to list deployments %v", err)
|
||||
}
|
||||
|
||||
items := make([]runtime.Object, len(deployments.Items))
|
||||
// Ensure we always have pod annotations to add to
|
||||
for i, v := range deployments.Items {
|
||||
if v.Spec.Template.ObjectMeta.Annotations == nil {
|
||||
annotations := make(map[string]string)
|
||||
deployments.Items[i].Spec.Template.ObjectMeta.Annotations = annotations
|
||||
}
|
||||
items[i] = &deployments.Items[i]
|
||||
}
|
||||
|
||||
return util.InterfaceSlice(deployments.Items)
|
||||
return items
|
||||
}
|
||||
|
||||
// GetDaemonSetItems returns the daemonSets in given namespace
|
||||
func GetDaemonSetItems(clients kube.Clients, namespace string) []interface{} {
|
||||
func GetDaemonSetItems(clients kube.Clients, namespace string) []runtime.Object {
|
||||
daemonSets, err := clients.KubernetesClient.AppsV1().DaemonSets(namespace).List(context.TODO(), meta_v1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to list daemonSets %v", err)
|
||||
}
|
||||
|
||||
items := make([]runtime.Object, len(daemonSets.Items))
|
||||
// Ensure we always have pod annotations to add to
|
||||
for i, v := range daemonSets.Items {
|
||||
if v.Spec.Template.ObjectMeta.Annotations == nil {
|
||||
daemonSets.Items[i].Spec.Template.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
items[i] = &daemonSets.Items[i]
|
||||
}
|
||||
|
||||
return util.InterfaceSlice(daemonSets.Items)
|
||||
return items
|
||||
}
|
||||
|
||||
// GetStatefulSetItems returns the statefulSets in given namespace
|
||||
func GetStatefulSetItems(clients kube.Clients, namespace string) []interface{} {
|
||||
func GetStatefulSetItems(clients kube.Clients, namespace string) []runtime.Object {
|
||||
statefulSets, err := clients.KubernetesClient.AppsV1().StatefulSets(namespace).List(context.TODO(), meta_v1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to list statefulSets %v", err)
|
||||
}
|
||||
|
||||
items := make([]runtime.Object, len(statefulSets.Items))
|
||||
// Ensure we always have pod annotations to add to
|
||||
for i, v := range statefulSets.Items {
|
||||
if v.Spec.Template.ObjectMeta.Annotations == nil {
|
||||
statefulSets.Items[i].Spec.Template.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
items[i] = &statefulSets.Items[i]
|
||||
}
|
||||
|
||||
return util.InterfaceSlice(statefulSets.Items)
|
||||
return items
|
||||
}
|
||||
|
||||
// GetDeploymentConfigItems returns the deploymentConfigs in given namespace
|
||||
func GetDeploymentConfigItems(clients kube.Clients, namespace string) []interface{} {
|
||||
func GetDeploymentConfigItems(clients kube.Clients, namespace string) []runtime.Object {
|
||||
deploymentConfigs, err := clients.OpenshiftAppsClient.AppsV1().DeploymentConfigs(namespace).List(context.TODO(), meta_v1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to list deploymentConfigs %v", err)
|
||||
}
|
||||
|
||||
items := make([]runtime.Object, len(deploymentConfigs.Items))
|
||||
// Ensure we always have pod annotations to add to
|
||||
for i, v := range deploymentConfigs.Items {
|
||||
if v.Spec.Template.ObjectMeta.Annotations == nil {
|
||||
deploymentConfigs.Items[i].Spec.Template.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
items[i] = &deploymentConfigs.Items[i]
|
||||
}
|
||||
|
||||
return util.InterfaceSlice(deploymentConfigs.Items)
|
||||
return items
|
||||
}
|
||||
|
||||
// GetRolloutItems returns the rollouts in given namespace
|
||||
func GetRolloutItems(clients kube.Clients, namespace string) []interface{} {
|
||||
func GetRolloutItems(clients kube.Clients, namespace string) []runtime.Object {
|
||||
rollouts, err := clients.ArgoRolloutClient.ArgoprojV1alpha1().Rollouts(namespace).List(context.TODO(), meta_v1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to list Rollouts %v", err)
|
||||
}
|
||||
|
||||
items := make([]runtime.Object, len(rollouts.Items))
|
||||
// Ensure we always have pod annotations to add to
|
||||
for i, v := range rollouts.Items {
|
||||
if v.Spec.Template.ObjectMeta.Annotations == nil {
|
||||
rollouts.Items[i].Spec.Template.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
items[i] = &rollouts.Items[i]
|
||||
}
|
||||
|
||||
return util.InterfaceSlice(rollouts.Items)
|
||||
return items
|
||||
}
|
||||
|
||||
// GetDeploymentAnnotations returns the annotations of given deployment
|
||||
func GetDeploymentAnnotations(item interface{}) map[string]string {
|
||||
return item.(appsv1.Deployment).ObjectMeta.Annotations
|
||||
func GetDeploymentAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*appsv1.Deployment).ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetDaemonSetAnnotations returns the annotations of given daemonSet
|
||||
func GetDaemonSetAnnotations(item interface{}) map[string]string {
|
||||
return item.(appsv1.DaemonSet).ObjectMeta.Annotations
|
||||
func GetDaemonSetAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*appsv1.DaemonSet).ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetStatefulSetAnnotations returns the annotations of given statefulSet
|
||||
func GetStatefulSetAnnotations(item interface{}) map[string]string {
|
||||
return item.(appsv1.StatefulSet).ObjectMeta.Annotations
|
||||
func GetStatefulSetAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*appsv1.StatefulSet).ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetDeploymentConfigAnnotations returns the annotations of given deploymentConfig
|
||||
func GetDeploymentConfigAnnotations(item interface{}) map[string]string {
|
||||
return item.(openshiftv1.DeploymentConfig).ObjectMeta.Annotations
|
||||
func GetDeploymentConfigAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*openshiftv1.DeploymentConfig).ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetRolloutAnnotations returns the annotations of given rollout
|
||||
func GetRolloutAnnotations(item interface{}) map[string]string {
|
||||
return item.(argorolloutv1alpha1.Rollout).ObjectMeta.Annotations
|
||||
func GetRolloutAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*argorolloutv1alpha1.Rollout).ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetDeploymentPodAnnotations returns the pod's annotations of given deployment
|
||||
func GetDeploymentPodAnnotations(item interface{}) map[string]string {
|
||||
return item.(appsv1.Deployment).Spec.Template.ObjectMeta.Annotations
|
||||
func GetDeploymentPodAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*appsv1.Deployment).Spec.Template.ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetDaemonSetPodAnnotations returns the pod's annotations of given daemonSet
|
||||
func GetDaemonSetPodAnnotations(item interface{}) map[string]string {
|
||||
return item.(appsv1.DaemonSet).Spec.Template.ObjectMeta.Annotations
|
||||
func GetDaemonSetPodAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*appsv1.DaemonSet).Spec.Template.ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetStatefulSetPodAnnotations returns the pod's annotations of given statefulSet
|
||||
func GetStatefulSetPodAnnotations(item interface{}) map[string]string {
|
||||
return item.(appsv1.StatefulSet).Spec.Template.ObjectMeta.Annotations
|
||||
func GetStatefulSetPodAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*appsv1.StatefulSet).Spec.Template.ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetDeploymentConfigPodAnnotations returns the pod's annotations of given deploymentConfig
|
||||
func GetDeploymentConfigPodAnnotations(item interface{}) map[string]string {
|
||||
return item.(openshiftv1.DeploymentConfig).Spec.Template.ObjectMeta.Annotations
|
||||
func GetDeploymentConfigPodAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*openshiftv1.DeploymentConfig).Spec.Template.ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetRolloutPodAnnotations returns the pod's annotations of given rollout
|
||||
func GetRolloutPodAnnotations(item interface{}) map[string]string {
|
||||
return item.(argorolloutv1alpha1.Rollout).Spec.Template.ObjectMeta.Annotations
|
||||
func GetRolloutPodAnnotations(item runtime.Object) map[string]string {
|
||||
return item.(*argorolloutv1alpha1.Rollout).Spec.Template.ObjectMeta.Annotations
|
||||
}
|
||||
|
||||
// GetDeploymentContainers returns the containers of given deployment
|
||||
func GetDeploymentContainers(item interface{}) []v1.Container {
|
||||
return item.(appsv1.Deployment).Spec.Template.Spec.Containers
|
||||
func GetDeploymentContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*appsv1.Deployment).Spec.Template.Spec.Containers
|
||||
}
|
||||
|
||||
// GetDaemonSetContainers returns the containers of given daemonSet
|
||||
func GetDaemonSetContainers(item interface{}) []v1.Container {
|
||||
return item.(appsv1.DaemonSet).Spec.Template.Spec.Containers
|
||||
func GetDaemonSetContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*appsv1.DaemonSet).Spec.Template.Spec.Containers
|
||||
}
|
||||
|
||||
// GetStatefulSetContainers returns the containers of given statefulSet
|
||||
func GetStatefulSetContainers(item interface{}) []v1.Container {
|
||||
return item.(appsv1.StatefulSet).Spec.Template.Spec.Containers
|
||||
func GetStatefulSetContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*appsv1.StatefulSet).Spec.Template.Spec.Containers
|
||||
}
|
||||
|
||||
// GetDeploymentConfigContainers returns the containers of given deploymentConfig
|
||||
func GetDeploymentConfigContainers(item interface{}) []v1.Container {
|
||||
return item.(openshiftv1.DeploymentConfig).Spec.Template.Spec.Containers
|
||||
func GetDeploymentConfigContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*openshiftv1.DeploymentConfig).Spec.Template.Spec.Containers
|
||||
}
|
||||
|
||||
// GetRolloutContainers returns the containers of given rollout
|
||||
func GetRolloutContainers(item interface{}) []v1.Container {
|
||||
return item.(argorolloutv1alpha1.Rollout).Spec.Template.Spec.Containers
|
||||
func GetRolloutContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*argorolloutv1alpha1.Rollout).Spec.Template.Spec.Containers
|
||||
}
|
||||
|
||||
// GetDeploymentInitContainers returns the containers of given deployment
|
||||
func GetDeploymentInitContainers(item interface{}) []v1.Container {
|
||||
return item.(appsv1.Deployment).Spec.Template.Spec.InitContainers
|
||||
func GetDeploymentInitContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*appsv1.Deployment).Spec.Template.Spec.InitContainers
|
||||
}
|
||||
|
||||
// GetDaemonSetInitContainers returns the containers of given daemonSet
|
||||
func GetDaemonSetInitContainers(item interface{}) []v1.Container {
|
||||
return item.(appsv1.DaemonSet).Spec.Template.Spec.InitContainers
|
||||
func GetDaemonSetInitContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*appsv1.DaemonSet).Spec.Template.Spec.InitContainers
|
||||
}
|
||||
|
||||
// GetStatefulSetInitContainers returns the containers of given statefulSet
|
||||
func GetStatefulSetInitContainers(item interface{}) []v1.Container {
|
||||
return item.(appsv1.StatefulSet).Spec.Template.Spec.InitContainers
|
||||
func GetStatefulSetInitContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*appsv1.StatefulSet).Spec.Template.Spec.InitContainers
|
||||
}
|
||||
|
||||
// GetDeploymentConfigInitContainers returns the containers of given deploymentConfig
|
||||
func GetDeploymentConfigInitContainers(item interface{}) []v1.Container {
|
||||
return item.(openshiftv1.DeploymentConfig).Spec.Template.Spec.InitContainers
|
||||
func GetDeploymentConfigInitContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*openshiftv1.DeploymentConfig).Spec.Template.Spec.InitContainers
|
||||
}
|
||||
|
||||
// GetRolloutInitContainers returns the containers of given rollout
|
||||
func GetRolloutInitContainers(item interface{}) []v1.Container {
|
||||
return item.(argorolloutv1alpha1.Rollout).Spec.Template.Spec.InitContainers
|
||||
func GetRolloutInitContainers(item runtime.Object) []v1.Container {
|
||||
return item.(*argorolloutv1alpha1.Rollout).Spec.Template.Spec.InitContainers
|
||||
}
|
||||
|
||||
// UpdateDeployment performs rolling upgrade on deployment
|
||||
func UpdateDeployment(clients kube.Clients, namespace string, resource interface{}) error {
|
||||
deployment := resource.(appsv1.Deployment)
|
||||
_, err := clients.KubernetesClient.AppsV1().Deployments(namespace).Update(context.TODO(), &deployment, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
func UpdateDeployment(clients kube.Clients, namespace string, resource runtime.Object) error {
|
||||
deployment := resource.(*appsv1.Deployment)
|
||||
_, err := clients.KubernetesClient.AppsV1().Deployments(namespace).Update(context.TODO(), deployment, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateDaemonSet performs rolling upgrade on daemonSet
|
||||
func UpdateDaemonSet(clients kube.Clients, namespace string, resource interface{}) error {
|
||||
daemonSet := resource.(appsv1.DaemonSet)
|
||||
_, err := clients.KubernetesClient.AppsV1().DaemonSets(namespace).Update(context.TODO(), &daemonSet, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
func UpdateDaemonSet(clients kube.Clients, namespace string, resource runtime.Object) error {
|
||||
daemonSet := resource.(*appsv1.DaemonSet)
|
||||
_, err := clients.KubernetesClient.AppsV1().DaemonSets(namespace).Update(context.TODO(), daemonSet, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateStatefulSet performs rolling upgrade on statefulSet
|
||||
func UpdateStatefulSet(clients kube.Clients, namespace string, resource interface{}) error {
|
||||
statefulSet := resource.(appsv1.StatefulSet)
|
||||
_, err := clients.KubernetesClient.AppsV1().StatefulSets(namespace).Update(context.TODO(), &statefulSet, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
func UpdateStatefulSet(clients kube.Clients, namespace string, resource runtime.Object) error {
|
||||
statefulSet := resource.(*appsv1.StatefulSet)
|
||||
_, err := clients.KubernetesClient.AppsV1().StatefulSets(namespace).Update(context.TODO(), statefulSet, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateDeploymentConfig performs rolling upgrade on deploymentConfig
|
||||
func UpdateDeploymentConfig(clients kube.Clients, namespace string, resource interface{}) error {
|
||||
deploymentConfig := resource.(openshiftv1.DeploymentConfig)
|
||||
_, err := clients.OpenshiftAppsClient.AppsV1().DeploymentConfigs(namespace).Update(context.TODO(), &deploymentConfig, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
func UpdateDeploymentConfig(clients kube.Clients, namespace string, resource runtime.Object) error {
|
||||
deploymentConfig := resource.(*openshiftv1.DeploymentConfig)
|
||||
_, err := clients.OpenshiftAppsClient.AppsV1().DeploymentConfigs(namespace).Update(context.TODO(), deploymentConfig, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateRollout performs rolling upgrade on rollout
|
||||
func UpdateRollout(clients kube.Clients, namespace string, resource interface{}) error {
|
||||
rollout := resource.(argorolloutv1alpha1.Rollout)
|
||||
func UpdateRollout(clients kube.Clients, namespace string, resource runtime.Object) error {
|
||||
rollout := resource.(*argorolloutv1alpha1.Rollout)
|
||||
rolloutBefore, _ := clients.ArgoRolloutClient.ArgoprojV1alpha1().Rollouts(namespace).Get(context.TODO(), rollout.Name, meta_v1.GetOptions{})
|
||||
logrus.Warnf("Before: %+v", rolloutBefore.Spec.Template.Spec.Containers[0].Env)
|
||||
logrus.Warnf("After: %+v", rollout.Spec.Template.Spec.Containers[0].Env)
|
||||
_, err := clients.ArgoRolloutClient.ArgoprojV1alpha1().Rollouts(namespace).Update(context.TODO(), &rollout, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
_, err := clients.ArgoRolloutClient.ArgoprojV1alpha1().Rollouts(namespace).Update(context.TODO(), rollout, meta_v1.UpdateOptions{FieldManager: "Reloader"})
|
||||
return err
|
||||
}
|
||||
|
||||
// GetDeploymentVolumes returns the Volumes of given deployment
|
||||
func GetDeploymentVolumes(item interface{}) []v1.Volume {
|
||||
return item.(appsv1.Deployment).Spec.Template.Spec.Volumes
|
||||
func GetDeploymentVolumes(item runtime.Object) []v1.Volume {
|
||||
return item.(*appsv1.Deployment).Spec.Template.Spec.Volumes
|
||||
}
|
||||
|
||||
// GetDaemonSetVolumes returns the Volumes of given daemonSet
|
||||
func GetDaemonSetVolumes(item interface{}) []v1.Volume {
|
||||
return item.(appsv1.DaemonSet).Spec.Template.Spec.Volumes
|
||||
func GetDaemonSetVolumes(item runtime.Object) []v1.Volume {
|
||||
return item.(*appsv1.DaemonSet).Spec.Template.Spec.Volumes
|
||||
}
|
||||
|
||||
// GetStatefulSetVolumes returns the Volumes of given statefulSet
|
||||
func GetStatefulSetVolumes(item interface{}) []v1.Volume {
|
||||
return item.(appsv1.StatefulSet).Spec.Template.Spec.Volumes
|
||||
func GetStatefulSetVolumes(item runtime.Object) []v1.Volume {
|
||||
return item.(*appsv1.StatefulSet).Spec.Template.Spec.Volumes
|
||||
}
|
||||
|
||||
// GetDeploymentConfigVolumes returns the Volumes of given deploymentConfig
|
||||
func GetDeploymentConfigVolumes(item interface{}) []v1.Volume {
|
||||
return item.(openshiftv1.DeploymentConfig).Spec.Template.Spec.Volumes
|
||||
func GetDeploymentConfigVolumes(item runtime.Object) []v1.Volume {
|
||||
return item.(*openshiftv1.DeploymentConfig).Spec.Template.Spec.Volumes
|
||||
}
|
||||
|
||||
// GetRolloutVolumes returns the Volumes of given rollout
|
||||
func GetRolloutVolumes(item interface{}) []v1.Volume {
|
||||
return item.(argorolloutv1alpha1.Rollout).Spec.Template.Spec.Volumes
|
||||
func GetRolloutVolumes(item runtime.Object) []v1.Volume {
|
||||
return item.(*argorolloutv1alpha1.Rollout).Spec.Template.Spec.Volumes
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/leadership"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stakater/Reloader/internal/pkg/controller"
|
||||
@@ -35,24 +38,38 @@ func NewReloaderCommand() *cobra.Command {
|
||||
cmd.PersistentFlags().StringVar(&options.LogFormat, "log-format", "", "Log format to use (empty string for text, or JSON")
|
||||
cmd.PersistentFlags().StringSlice("resources-to-ignore", []string{}, "list of resources to ignore (valid options 'configMaps' or 'secrets')")
|
||||
cmd.PersistentFlags().StringSlice("namespaces-to-ignore", []string{}, "list of namespaces to ignore")
|
||||
cmd.PersistentFlags().StringSlice("namespace-selector", []string{}, "list of key:vaule namespace labels to include")
|
||||
cmd.PersistentFlags().StringVar(&options.IsArgoRollouts, "is-Argo-Rollouts", "false", "Add support for argo rollouts")
|
||||
cmd.PersistentFlags().StringVar(&options.ReloadStrategy, constants.ReloadStrategyFlag, constants.EnvVarsReloadStrategy, "Specifies the desired reload strategy")
|
||||
cmd.PersistentFlags().StringVar(&options.ReloadOnCreate, "reload-on-create", "false", "Add support to watch create events")
|
||||
cmd.PersistentFlags().BoolVar(&options.EnableHA, "enable-ha", false, "Adds support for running multiple replicas via leadership election")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func validateFlags(*cobra.Command, []string) error {
|
||||
// Ensure the reload strategy is one of the following...
|
||||
var validReloadStrategy bool
|
||||
valid := []string{constants.EnvVarsReloadStrategy, constants.AnnotationsReloadStrategy}
|
||||
for _, s := range valid {
|
||||
if s == options.ReloadStrategy {
|
||||
return nil
|
||||
validReloadStrategy = true
|
||||
}
|
||||
}
|
||||
|
||||
err := fmt.Sprintf("%s must be one of: %s", constants.ReloadStrategyFlag, strings.Join(valid, ", "))
|
||||
return errors.New(err)
|
||||
if !validReloadStrategy {
|
||||
err := fmt.Sprintf("%s must be one of: %s", constants.ReloadStrategyFlag, strings.Join(valid, ", "))
|
||||
return errors.New(err)
|
||||
}
|
||||
|
||||
// Validate that HA options are correct
|
||||
if options.EnableHA {
|
||||
if err := validateHAEnvs(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func configureLogging(logFormat string) error {
|
||||
@@ -68,6 +85,25 @@ func configureLogging(logFormat string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateHAEnvs() error {
|
||||
podName, podNamespace := getHAEnvs()
|
||||
|
||||
if podName == "" {
|
||||
return fmt.Errorf("%s not set, cannot run in HA mode without %s set", constants.PodNameEnv, constants.PodNameEnv)
|
||||
}
|
||||
if podNamespace == "" {
|
||||
return fmt.Errorf("%s not set, cannot run in HA mode without %s set", constants.PodNamespaceEnv, constants.PodNamespaceEnv)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHAEnvs() (string, string) {
|
||||
podName := os.Getenv(constants.PodNameEnv)
|
||||
podNamespace := os.Getenv(constants.PodNamespaceEnv)
|
||||
|
||||
return podName, podNamespace
|
||||
}
|
||||
|
||||
func startReloader(cmd *cobra.Command, args []string) {
|
||||
err := configureLogging(options.LogFormat)
|
||||
if err != nil {
|
||||
@@ -97,18 +133,34 @@ func startReloader(cmd *cobra.Command, args []string) {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
namespaceLabelSelector, err := getNamespaceLabelSelector(cmd)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if len(namespaceLabelSelector) > 0 {
|
||||
logrus.Warnf("namespace-selector is set, will detect changes in namespaces with these labels: %s.", namespaceLabelSelector)
|
||||
}
|
||||
|
||||
collectors := metrics.SetupPrometheusEndpoint()
|
||||
|
||||
var controllers []*controller.Controller
|
||||
for k := range kube.ResourceMap {
|
||||
if ignoredResourcesList.Contains(k) {
|
||||
continue
|
||||
}
|
||||
|
||||
c, err := controller.NewController(clientset, k, currentNamespace, ignoredNamespacesList, collectors)
|
||||
c, err := controller.NewController(clientset, k, currentNamespace, ignoredNamespacesList, namespaceLabelSelector, collectors)
|
||||
if err != nil {
|
||||
logrus.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
controllers = append(controllers, c)
|
||||
|
||||
// If HA is enabled we only run the controller when
|
||||
if options.EnableHA {
|
||||
continue
|
||||
}
|
||||
// Now let's start the controller
|
||||
stop := make(chan struct{})
|
||||
defer close(stop)
|
||||
@@ -116,14 +168,37 @@ func startReloader(cmd *cobra.Command, args []string) {
|
||||
go c.Run(1, stop)
|
||||
}
|
||||
|
||||
// Wait forever
|
||||
select {}
|
||||
// Run leadership election
|
||||
if options.EnableHA {
|
||||
podName, podNamespace := getHAEnvs()
|
||||
lock := leadership.GetNewLock(clientset.CoordinationV1(), constants.LockName, podName, podNamespace)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
go leadership.RunLeaderElection(lock, ctx, cancel, podName, controllers)
|
||||
}
|
||||
|
||||
logrus.Fatal(leadership.Healthz())
|
||||
}
|
||||
|
||||
func getIgnoredNamespacesList(cmd *cobra.Command) (util.List, error) {
|
||||
return getStringSliceFromFlags(cmd, "namespaces-to-ignore")
|
||||
}
|
||||
|
||||
func getNamespaceLabelSelector(cmd *cobra.Command) (util.Map, error) {
|
||||
slice, err := getStringSliceFromFlags(cmd, "namespace-selector")
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
var namespaceSelectorMap util.Map = make(util.Map)
|
||||
for _, kv := range slice {
|
||||
split := strings.Split(kv, ":")
|
||||
namespaceSelectorMap[split[0]] = split[1]
|
||||
}
|
||||
|
||||
return namespaceSelectorMap, nil
|
||||
}
|
||||
|
||||
func getStringSliceFromFlags(cmd *cobra.Command, flag string) ([]string, error) {
|
||||
slice, err := cmd.Flags().GetStringSlice(flag)
|
||||
if err != nil {
|
||||
|
||||
@@ -20,3 +20,10 @@ const (
|
||||
// AnnotationsReloadStrategy instructs Reloader to add pod template annotations to facilitate a restart
|
||||
AnnotationsReloadStrategy = "annotations"
|
||||
)
|
||||
|
||||
// Leadership election related consts
|
||||
const (
|
||||
LockName string = "stakater-reloader-lock"
|
||||
PodNameEnv string = "POD_NAME"
|
||||
PodNamespaceEnv string = "POD_NAMESPACE"
|
||||
)
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/stakater/Reloader/internal/pkg/options"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/handler"
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
"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"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/kubectl/pkg/scheme"
|
||||
)
|
||||
|
||||
// Controller for checking events
|
||||
@@ -29,6 +33,8 @@ type Controller struct {
|
||||
namespace string
|
||||
ignoredNamespaces util.List
|
||||
collectors metrics.Collectors
|
||||
recorder record.EventRecorder
|
||||
namespaceSelector map[string]string
|
||||
}
|
||||
|
||||
// controllerInitialized flag determines whether controlled is being initialized
|
||||
@@ -36,13 +42,19 @@ var controllerInitialized bool = false
|
||||
|
||||
// NewController for initializing a Controller
|
||||
func NewController(
|
||||
client kubernetes.Interface, resource string, namespace string, ignoredNamespaces []string, collectors metrics.Collectors) (*Controller, error) {
|
||||
client kubernetes.Interface, resource string, namespace string, ignoredNamespaces []string, namespaceLabelSelector map[string]string, collectors metrics.Collectors) (*Controller, error) {
|
||||
|
||||
c := Controller{
|
||||
client: client,
|
||||
namespace: namespace,
|
||||
ignoredNamespaces: ignoredNamespaces,
|
||||
namespaceSelector: namespaceLabelSelector,
|
||||
}
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{
|
||||
Interface: client.CoreV1().Events(""),
|
||||
})
|
||||
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: fmt.Sprintf("reloader-%s", resource)})
|
||||
|
||||
queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
|
||||
listWatcher := cache.NewListWatchFromClient(client.CoreV1().RESTClient(), resource, namespace, fields.Everything())
|
||||
@@ -56,16 +68,20 @@ func NewController(
|
||||
c.informer = informer
|
||||
c.queue = queue
|
||||
c.collectors = collectors
|
||||
c.recorder = recorder
|
||||
|
||||
logrus.Infof("created controller for: %s", resource)
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// Add function to add a new object to the queue in case of creating a resource
|
||||
func (c *Controller) Add(obj interface{}) {
|
||||
if options.ReloadOnCreate == "true" {
|
||||
if !c.resourceInIgnoredNamespace(obj) && controllerInitialized {
|
||||
if !c.resourceInIgnoredNamespace(obj) && c.resourceInNamespaceSelector(obj) && controllerInitialized {
|
||||
c.queue.Add(handler.ResourceCreatedHandler{
|
||||
Resource: obj,
|
||||
Collectors: c.collectors,
|
||||
Recorder: c.recorder,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -81,13 +97,50 @@ func (c *Controller) resourceInIgnoredNamespace(raw interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Controller) resourceInNamespaceSelector(raw interface{}) bool {
|
||||
if len(c.namespaceSelector) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
switch object := raw.(type) {
|
||||
case *v1.ConfigMap:
|
||||
return c.matchLabels(object.ObjectMeta.Namespace)
|
||||
case *v1.Secret:
|
||||
return c.matchLabels(object.ObjectMeta.Namespace)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Controller) matchLabels(resourceNamespace string) bool {
|
||||
namespace, err := c.client.CoreV1().Namespaces().Get(context.Background(), resourceNamespace, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Warn(err)
|
||||
return false
|
||||
}
|
||||
|
||||
for selectorKey, selectorVal := range c.namespaceSelector {
|
||||
|
||||
namespaceLabelVal, namespaceLabelKeyExists := namespace.ObjectMeta.Labels[selectorKey]
|
||||
|
||||
if namespaceLabelKeyExists && selectorVal == "*" {
|
||||
continue
|
||||
}
|
||||
|
||||
if !namespaceLabelKeyExists || selectorVal != namespaceLabelVal {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Update function to add an old object and a new object to the queue in case of updating a resource
|
||||
func (c *Controller) Update(old interface{}, new interface{}) {
|
||||
if !c.resourceInIgnoredNamespace(new) {
|
||||
if !c.resourceInIgnoredNamespace(new) && c.resourceInNamespaceSelector(new) {
|
||||
c.queue.Add(handler.ResourceUpdatedHandler{
|
||||
Resource: new,
|
||||
OldResource: old,
|
||||
Collectors: c.collectors,
|
||||
Recorder: c.recorder,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -97,7 +150,7 @@ func (c *Controller) Delete(old interface{}) {
|
||||
// Todo: Any future delete event can be handled here
|
||||
}
|
||||
|
||||
//Run function for controller which handles the queue
|
||||
// Run function for controller which handles the queue
|
||||
func (c *Controller) Run(threadiness int, stopCh chan struct{}) {
|
||||
defer runtime.HandleCrash()
|
||||
|
||||
@@ -169,5 +222,6 @@ func (c *Controller) handleErr(err error, key interface{}) {
|
||||
c.queue.Forget(key)
|
||||
// Report to an external entity that, even after several retries, we could not successfully process this key
|
||||
runtime.HandleError(err)
|
||||
logrus.Infof("Dropping the key %q out of the queue: %v", key, err)
|
||||
logrus.Errorf("Dropping key out of the queue: %v", err)
|
||||
logrus.Debugf("Dropping the key %q out of the queue: %v", key, err)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -14,7 +16,10 @@ import (
|
||||
"github.com/stakater/Reloader/internal/pkg/testutil"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
"github.com/stakater/Reloader/pkg/kube"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
)
|
||||
@@ -40,7 +45,7 @@ func TestMain(m *testing.M) {
|
||||
|
||||
logrus.Infof("Creating controller")
|
||||
for k := range kube.ResourceMap {
|
||||
c, err := NewController(clients.KubernetesClient, k, namespace, []string{}, collectors)
|
||||
c, err := NewController(clients.KubernetesClient, k, namespace, []string{}, map[string]string{}, collectors)
|
||||
if err != nil {
|
||||
logrus.Fatalf("%s", err)
|
||||
}
|
||||
@@ -2279,3 +2284,143 @@ func TestController_resourceInIgnoredNamespace(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestController_resourceInNamespaceSelector(t *testing.T) {
|
||||
type fields struct {
|
||||
indexer cache.Indexer
|
||||
queue workqueue.RateLimitingInterface
|
||||
informer cache.Controller
|
||||
namespace v1.Namespace
|
||||
namespaceSelector util.Map
|
||||
}
|
||||
type args struct {
|
||||
raw interface{}
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "TestConfigMapResourceInNamespaceSelector",
|
||||
fields: fields{
|
||||
namespaceSelector: util.Map{
|
||||
"select": "this",
|
||||
"select2": "this2",
|
||||
},
|
||||
namespace: v1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "selected-namespace",
|
||||
Labels: map[string]string{
|
||||
"select": "this",
|
||||
"select2": "this2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
raw: testutil.GetConfigmap("selected-namespace", "testcm", "test"),
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "TestConfigMapResourceNotInNamespaceSelector",
|
||||
fields: fields{
|
||||
namespaceSelector: util.Map{
|
||||
"select": "this",
|
||||
"select2": "this2",
|
||||
},
|
||||
namespace: v1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "not-selected-namespace",
|
||||
Labels: map[string]string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
raw: testutil.GetConfigmap("not-selected-namespace", "testcm", "test"),
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "TestSecretResourceInNamespaceSelector",
|
||||
fields: fields{
|
||||
namespaceSelector: util.Map{
|
||||
"select": "this",
|
||||
"select2": "this2",
|
||||
},
|
||||
namespace: v1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "selected-namespace",
|
||||
Labels: map[string]string{
|
||||
"select": "this",
|
||||
"select2": "this2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
raw: testutil.GetSecret("selected-namespace", "testsecret", "test"),
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "TestSecretResourceNotInNamespaceSelector",
|
||||
fields: fields{
|
||||
namespaceSelector: util.Map{
|
||||
"select": "this",
|
||||
"select2": "this2",
|
||||
},
|
||||
namespace: v1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "not-selected-namespace",
|
||||
Labels: map[string]string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
raw: testutil.GetSecret("not-selected-namespace", "secret", "test"),
|
||||
},
|
||||
want: false,
|
||||
}, {
|
||||
name: "TestSecretResourceInNamespaceSelectorWiledcardValue",
|
||||
fields: fields{
|
||||
namespaceSelector: util.Map{
|
||||
"select": "*",
|
||||
},
|
||||
namespace: v1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "selected-namespace",
|
||||
Labels: map[string]string{
|
||||
"select": "this",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
raw: testutil.GetSecret("selected-namespace", "secret", "test"),
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fakeClient := fake.NewSimpleClientset()
|
||||
namespace, _ := fakeClient.CoreV1().Namespaces().Create(context.Background(), &tt.fields.namespace, metav1.CreateOptions{})
|
||||
logrus.Infof("created fakeClient namesapce for testing = %s", namespace.Name)
|
||||
|
||||
c := &Controller{
|
||||
client: fakeClient,
|
||||
indexer: tt.fields.indexer,
|
||||
queue: tt.fields.queue,
|
||||
informer: tt.fields.informer,
|
||||
namespace: tt.fields.namespace.ObjectMeta.Name,
|
||||
namespaceSelector: tt.fields.namespaceSelector,
|
||||
}
|
||||
|
||||
if got := c.resourceInNamespaceSelector(tt.args.raw); got != tt.want {
|
||||
t.Errorf("Controller.resourceInNamespaceSelector() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@ import (
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
)
|
||||
|
||||
// ResourceCreatedHandler contains new objects
|
||||
type ResourceCreatedHandler struct {
|
||||
Resource interface{}
|
||||
Collectors metrics.Collectors
|
||||
Recorder record.EventRecorder
|
||||
}
|
||||
|
||||
// Handle processes the newly created resource
|
||||
@@ -20,7 +22,7 @@ func (r ResourceCreatedHandler) Handle() error {
|
||||
} else {
|
||||
config, _ := r.GetConfig()
|
||||
// process resource based on its type
|
||||
return doRollingUpgrade(config, r.Collectors)
|
||||
return doRollingUpgrade(config, r.Collectors, r.Recorder)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
)
|
||||
|
||||
// ResourceUpdatedHandler contains updated objects
|
||||
@@ -12,6 +13,7 @@ type ResourceUpdatedHandler struct {
|
||||
Resource interface{}
|
||||
OldResource interface{}
|
||||
Collectors metrics.Collectors
|
||||
Recorder record.EventRecorder
|
||||
}
|
||||
|
||||
// Handle processes the updated resource
|
||||
@@ -22,7 +24,7 @@ func (r ResourceUpdatedHandler) Handle() error {
|
||||
config, oldSHAData := r.GetConfig()
|
||||
if config.SHAValue != oldSHAData {
|
||||
// process resource based on its type
|
||||
return doRollingUpgrade(config, r.Collectors)
|
||||
return doRollingUpgrade(config, r.Collectors, r.Recorder)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -4,8 +4,14 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/sirupsen/logrus"
|
||||
alert "github.com/stakater/Reloader/internal/pkg/alerts"
|
||||
"github.com/stakater/Reloader/internal/pkg/callbacks"
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
@@ -13,8 +19,9 @@ import (
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
"github.com/stakater/Reloader/pkg/kube"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"strconv"
|
||||
"strings"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/tools/record"
|
||||
)
|
||||
|
||||
// GetDeploymentRollingUpgradeFuncs returns all callback funcs for a deployment
|
||||
@@ -87,31 +94,31 @@ func GetArgoRolloutRollingUpgradeFuncs() callbacks.RollingUpgradeFuncs {
|
||||
}
|
||||
}
|
||||
|
||||
func doRollingUpgrade(config util.Config, collectors metrics.Collectors) error {
|
||||
func doRollingUpgrade(config util.Config, collectors metrics.Collectors, recorder record.EventRecorder) error {
|
||||
clients := kube.GetClients()
|
||||
|
||||
err := rollingUpgrade(clients, config, GetDeploymentRollingUpgradeFuncs(), collectors)
|
||||
err := rollingUpgrade(clients, config, GetDeploymentRollingUpgradeFuncs(), collectors, recorder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = rollingUpgrade(clients, config, GetDaemonSetRollingUpgradeFuncs(), collectors)
|
||||
err = rollingUpgrade(clients, config, GetDaemonSetRollingUpgradeFuncs(), collectors, recorder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = rollingUpgrade(clients, config, GetStatefulSetRollingUpgradeFuncs(), collectors)
|
||||
err = rollingUpgrade(clients, config, GetStatefulSetRollingUpgradeFuncs(), collectors, recorder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if kube.IsOpenshift {
|
||||
err = rollingUpgrade(clients, config, GetDeploymentConfigRollingUpgradeFuncs(), collectors)
|
||||
err = rollingUpgrade(clients, config, GetDeploymentConfigRollingUpgradeFuncs(), collectors, recorder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if options.IsArgoRollouts == "true" {
|
||||
err = rollingUpgrade(clients, config, GetArgoRolloutRollingUpgradeFuncs(), collectors)
|
||||
err = rollingUpgrade(clients, config, GetArgoRolloutRollingUpgradeFuncs(), collectors, recorder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -120,9 +127,9 @@ func doRollingUpgrade(config util.Config, collectors metrics.Collectors) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func rollingUpgrade(clients kube.Clients, config util.Config, upgradeFuncs callbacks.RollingUpgradeFuncs, collectors metrics.Collectors) error {
|
||||
func rollingUpgrade(clients kube.Clients, config util.Config, upgradeFuncs callbacks.RollingUpgradeFuncs, collectors metrics.Collectors, recorder record.EventRecorder) error {
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, upgradeFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, upgradeFuncs, collectors, recorder)
|
||||
if err != nil {
|
||||
logrus.Errorf("Rolling upgrade for '%s' failed with error = %v", config.ResourceName, err)
|
||||
}
|
||||
@@ -130,7 +137,7 @@ func rollingUpgrade(clients kube.Clients, config util.Config, upgradeFuncs callb
|
||||
}
|
||||
|
||||
// PerformRollingUpgrade upgrades the deployment if there is any change in configmap or secret data
|
||||
func PerformRollingUpgrade(clients kube.Clients, config util.Config, upgradeFuncs callbacks.RollingUpgradeFuncs, collectors metrics.Collectors) error {
|
||||
func PerformRollingUpgrade(clients kube.Clients, config util.Config, upgradeFuncs callbacks.RollingUpgradeFuncs, collectors metrics.Collectors, recorder record.EventRecorder) error {
|
||||
items := upgradeFuncs.ItemsFunc(clients, config.Namespace)
|
||||
|
||||
for _, i := range items {
|
||||
@@ -154,8 +161,9 @@ func PerformRollingUpgrade(clients kube.Clients, config util.Config, upgradeFunc
|
||||
if result != constants.Updated && annotationValue != "" {
|
||||
values := strings.Split(annotationValue, ",")
|
||||
for _, value := range values {
|
||||
value = strings.Trim(value, " ")
|
||||
if value == config.ResourceName {
|
||||
value = strings.TrimSpace(value)
|
||||
re := regexp.MustCompile("^" + value + "$")
|
||||
if re.Match([]byte(config.ResourceName)) {
|
||||
result = invokeReloadStrategy(upgradeFuncs, i, config, false)
|
||||
if result == constants.Updated {
|
||||
break
|
||||
@@ -172,16 +180,35 @@ func PerformRollingUpgrade(clients kube.Clients, config util.Config, upgradeFunc
|
||||
}
|
||||
|
||||
if result == constants.Updated {
|
||||
err = upgradeFuncs.UpdateFunc(clients, config.Namespace, i)
|
||||
resourceName := util.ToObjectMeta(i).Name
|
||||
accessor, err := meta.Accessor(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)
|
||||
return err
|
||||
}
|
||||
resourceName := accessor.GetName()
|
||||
err = upgradeFuncs.UpdateFunc(clients, config.Namespace, i)
|
||||
if err != nil {
|
||||
message := fmt.Sprintf("Update for '%s' of type '%s' in namespace '%s' failed with error %v", resourceName, upgradeFuncs.ResourceType, config.Namespace, err)
|
||||
logrus.Errorf(message)
|
||||
collectors.Reloaded.With(prometheus.Labels{"success": "false"}).Inc()
|
||||
if recorder != nil {
|
||||
recorder.Event(i, v1.EventTypeWarning, "ReloadFail", message)
|
||||
}
|
||||
return 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)
|
||||
message := fmt.Sprintf("Changes detected in '%s' of type '%s' in namespace '%s'", config.ResourceName, config.Type, config.Namespace)
|
||||
message += fmt.Sprintf(", Updated '%s' of type '%s' in namespace '%s'", resourceName, upgradeFuncs.ResourceType, config.Namespace)
|
||||
logrus.Infof(message)
|
||||
collectors.Reloaded.With(prometheus.Labels{"success": "true"}).Inc()
|
||||
alert_on_reload, ok := os.LookupEnv("ALERT_ON_RELOAD")
|
||||
if recorder != nil {
|
||||
recorder.Event(i, v1.EventTypeNormal, "Reloaded", message)
|
||||
}
|
||||
if ok && alert_on_reload == "true" {
|
||||
msg := fmt.Sprintf(
|
||||
"Reloader detected changes in *%s* of type *%s* in namespace *%s*. Hence reloaded *%s* of type *%s* in namespace *%s*",
|
||||
config.ResourceName, config.Type, config.Namespace, resourceName, upgradeFuncs.ResourceType, config.Namespace)
|
||||
alert.SendWebhookAlert(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,7 +286,7 @@ func getContainerWithEnvReference(containers []v1.Container, resourceName string
|
||||
return nil
|
||||
}
|
||||
|
||||
func getContainerUsingResource(upgradeFuncs callbacks.RollingUpgradeFuncs, item interface{}, config util.Config, autoReload bool) *v1.Container {
|
||||
func getContainerUsingResource(upgradeFuncs callbacks.RollingUpgradeFuncs, item runtime.Object, config util.Config, autoReload bool) *v1.Container {
|
||||
volumes := upgradeFuncs.VolumesFunc(item)
|
||||
containers := upgradeFuncs.ContainersFunc(item)
|
||||
initContainers := upgradeFuncs.InitContainersFunc(item)
|
||||
@@ -298,7 +325,7 @@ func getContainerUsingResource(upgradeFuncs callbacks.RollingUpgradeFuncs, item
|
||||
return container
|
||||
}
|
||||
|
||||
func invokeReloadStrategy(upgradeFuncs callbacks.RollingUpgradeFuncs, item interface{}, config util.Config, autoReload bool) constants.Result {
|
||||
func invokeReloadStrategy(upgradeFuncs callbacks.RollingUpgradeFuncs, item runtime.Object, config util.Config, autoReload bool) constants.Result {
|
||||
if options.ReloadStrategy == constants.AnnotationsReloadStrategy {
|
||||
return updatePodAnnotations(upgradeFuncs, item, config, autoReload)
|
||||
}
|
||||
@@ -306,7 +333,7 @@ func invokeReloadStrategy(upgradeFuncs callbacks.RollingUpgradeFuncs, item inter
|
||||
return updateContainerEnvVars(upgradeFuncs, item, config, autoReload)
|
||||
}
|
||||
|
||||
func updatePodAnnotations(upgradeFuncs callbacks.RollingUpgradeFuncs, item interface{}, config util.Config, autoReload bool) constants.Result {
|
||||
func updatePodAnnotations(upgradeFuncs callbacks.RollingUpgradeFuncs, item runtime.Object, config util.Config, autoReload bool) constants.Result {
|
||||
container := getContainerUsingResource(upgradeFuncs, item, config, autoReload)
|
||||
if container == nil {
|
||||
return constants.NoContainerFound
|
||||
@@ -358,7 +385,7 @@ func createReloadedAnnotations(target *util.ReloadSource) (map[string]string, er
|
||||
return annotations, nil
|
||||
}
|
||||
|
||||
func updateContainerEnvVars(upgradeFuncs callbacks.RollingUpgradeFuncs, item interface{}, config util.Config, autoReload bool) constants.Result {
|
||||
func updateContainerEnvVars(upgradeFuncs callbacks.RollingUpgradeFuncs, item runtime.Object, config util.Config, autoReload bool) constants.Result {
|
||||
var result constants.Result
|
||||
envVar := constants.EnvVarPrefix + util.ConvertToEnvVarName(config.ResourceName) + "_" + config.Type
|
||||
container := getContainerUsingResource(upgradeFuncs, item, config, autoReload)
|
||||
|
||||
@@ -16,7 +16,9 @@ import (
|
||||
"github.com/stakater/Reloader/internal/pkg/testutil"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
"github.com/stakater/Reloader/pkg/kube"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
testclient "k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
@@ -1186,7 +1188,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapUsingArs(t *testing.T) {
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
@@ -1211,7 +1213,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapInProjectedVolumeUsingArs(t *te
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap in projected volume")
|
||||
}
|
||||
@@ -1236,7 +1238,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapViaSearchAnnotationUsingArs(t *
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
}
|
||||
@@ -1261,7 +1263,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapViaSearchAnnotationNoTriggersUs
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
}
|
||||
@@ -1301,7 +1303,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapViaSearchAnnotationNotMappedUsi
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err = PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err = PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
}
|
||||
@@ -1325,7 +1327,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapInInitContainerUsingArs(t *test
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
@@ -1350,7 +1352,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapInProjectVolumeInInitContainerU
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap in projected volume")
|
||||
@@ -1375,7 +1377,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapAsEnvVarUsingArs(t *testing.T)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap used as env var")
|
||||
@@ -1400,7 +1402,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapAsEnvVarInInitContainerUsingArs
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap used as env var")
|
||||
@@ -1425,7 +1427,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapAsEnvVarFromUsingArs(t *testing
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap used as env var")
|
||||
@@ -1450,7 +1452,7 @@ func TestRollingUpgradeForDeploymentWithSecretUsingArs(t *testing.T) {
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -1475,7 +1477,7 @@ func TestRollingUpgradeForDeploymentWithSecretInProjectedVolumeUsingArs(t *testi
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret in projected volume")
|
||||
@@ -1500,7 +1502,7 @@ func TestRollingUpgradeForDeploymentWithSecretinInitContainerUsingArs(t *testing
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -1525,7 +1527,7 @@ func TestRollingUpgradeForDeploymentWithSecretInProjectedVolumeinInitContainerUs
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret in projected volume")
|
||||
@@ -1550,7 +1552,7 @@ func TestRollingUpgradeForDeploymentWithSecretAsEnvVarUsingArs(t *testing.T) {
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -1575,7 +1577,7 @@ func TestRollingUpgradeForDeploymentWithSecretAsEnvVarFromUsingArs(t *testing.T)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -1600,7 +1602,7 @@ func TestRollingUpgradeForDeploymentWithSecretAsEnvVarInInitContainerUsingArs(t
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -1625,7 +1627,7 @@ func TestRollingUpgradeForDaemonSetWithConfigmapUsingArs(t *testing.T) {
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with configmap")
|
||||
@@ -1650,7 +1652,7 @@ func TestRollingUpgradeForDaemonSetWithConfigmapInProjectedVolumeUsingArs(t *tes
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with configmap in projected volume")
|
||||
@@ -1675,7 +1677,7 @@ func TestRollingUpgradeForDaemonSetWithConfigmapAsEnvVarUsingArs(t *testing.T) {
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with configmap used as env var")
|
||||
@@ -1700,7 +1702,7 @@ func TestRollingUpgradeForDaemonSetWithSecretUsingArs(t *testing.T) {
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with secret")
|
||||
@@ -1725,7 +1727,7 @@ func TestRollingUpgradeForDaemonSetWithSecretInProjectedVolumeUsingArs(t *testin
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with secret in projected volume")
|
||||
@@ -1750,7 +1752,7 @@ func TestRollingUpgradeForStatefulSetWithConfigmapUsingArs(t *testing.T) {
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for StatefulSet with configmap")
|
||||
@@ -1775,7 +1777,7 @@ func TestRollingUpgradeForStatefulSetWithConfigmapInProjectedVolumeUsingArs(t *t
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for StatefulSet with configmap in projected volume")
|
||||
@@ -1800,7 +1802,7 @@ func TestRollingUpgradeForStatefulSetWithSecretUsingArs(t *testing.T) {
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for StatefulSet with secret")
|
||||
@@ -1825,7 +1827,7 @@ func TestRollingUpgradeForStatefulSetWithSecretInProjectedVolumeUsingArs(t *test
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for StatefulSet with secret in projected volume")
|
||||
@@ -1850,7 +1852,7 @@ func TestRollingUpgradeForDeploymentWithPodAnnotationsUsingArs(t *testing.T) {
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with pod annotations")
|
||||
@@ -1860,7 +1862,11 @@ func TestRollingUpgradeForDeploymentWithPodAnnotationsUsingArs(t *testing.T) {
|
||||
items := deploymentFuncs.ItemsFunc(clients, config.Namespace)
|
||||
var foundPod, foundBoth bool
|
||||
for _, i := range items {
|
||||
name := util.ToObjectMeta(i).Name
|
||||
accessor, err := meta.Accessor(i)
|
||||
if err != nil {
|
||||
t.Errorf("Error getting accessor for item: %v", err)
|
||||
}
|
||||
name := accessor.GetName()
|
||||
if name == arsConfigmapWithPodAnnotations {
|
||||
annotations := deploymentFuncs.PodAnnotationsFunc(i)
|
||||
updated := testutil.GetResourceSHAFromAnnotation(annotations)
|
||||
@@ -1896,12 +1902,12 @@ func TestFailedRollingUpgradeUsingArs(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, arsNamespace, arsConfigmapName, "fail.stakater.com")
|
||||
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, arsConfigmapName, shaData, options.ConfigmapUpdateOnChangeAnnotation)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
deploymentFuncs.UpdateFunc = func(_ kube.Clients, _ string, _ interface{}) error {
|
||||
deploymentFuncs.UpdateFunc = func(_ kube.Clients, _ string, _ runtime.Object) error {
|
||||
return fmt.Errorf("error")
|
||||
}
|
||||
collectors := getCollectors()
|
||||
|
||||
_ = PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
_ = PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
|
||||
if promtestutil.ToFloat64(collectors.Reloaded.With(labelFailed)) != 1 {
|
||||
t.Errorf("Counter was not increased")
|
||||
@@ -1916,7 +1922,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapUsingErs(t *testing.T) {
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
@@ -1941,7 +1947,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapInProjectedVolumeUsingErs(t *te
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap in projected volume")
|
||||
}
|
||||
@@ -1966,7 +1972,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapViaSearchAnnotationUsingErs(t *
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
}
|
||||
@@ -1991,7 +1997,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapViaSearchAnnotationNoTriggersUs
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
}
|
||||
@@ -2031,7 +2037,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapViaSearchAnnotationNotMappedUsi
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err = PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err = PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
}
|
||||
@@ -2055,7 +2061,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapInInitContainerUsingErs(t *test
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap")
|
||||
@@ -2080,7 +2086,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapInProjectVolumeInInitContainerU
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap in projected volume")
|
||||
@@ -2105,7 +2111,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapAsEnvVarUsingErs(t *testing.T)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap used as env var")
|
||||
@@ -2130,7 +2136,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapAsEnvVarInInitContainerUsingErs
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap used as env var")
|
||||
@@ -2155,7 +2161,7 @@ func TestRollingUpgradeForDeploymentWithConfigmapAsEnvVarFromUsingErs(t *testing
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Configmap used as env var")
|
||||
@@ -2180,7 +2186,7 @@ func TestRollingUpgradeForDeploymentWithSecretUsingErs(t *testing.T) {
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -2205,7 +2211,7 @@ func TestRollingUpgradeForDeploymentWithSecretInProjectedVolumeUsingErs(t *testi
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret in projected volume")
|
||||
@@ -2230,7 +2236,7 @@ func TestRollingUpgradeForDeploymentWithSecretinInitContainerUsingErs(t *testing
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -2255,7 +2261,7 @@ func TestRollingUpgradeForDeploymentWithSecretInProjectedVolumeinInitContainerUs
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret in projected volume")
|
||||
@@ -2280,7 +2286,7 @@ func TestRollingUpgradeForDeploymentWithSecretAsEnvVarUsingErs(t *testing.T) {
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -2305,7 +2311,7 @@ func TestRollingUpgradeForDeploymentWithSecretAsEnvVarFromUsingErs(t *testing.T)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -2330,7 +2336,7 @@ func TestRollingUpgradeForDeploymentWithSecretAsEnvVarInInitContainerUsingErs(t
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with Secret")
|
||||
@@ -2355,7 +2361,7 @@ func TestRollingUpgradeForDaemonSetWithConfigmapUsingErs(t *testing.T) {
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with configmap")
|
||||
@@ -2380,7 +2386,7 @@ func TestRollingUpgradeForDaemonSetWithConfigmapInProjectedVolumeUsingErs(t *tes
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with configmap in projected volume")
|
||||
@@ -2405,7 +2411,7 @@ func TestRollingUpgradeForDaemonSetWithConfigmapAsEnvVarUsingErs(t *testing.T) {
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with configmap used as env var")
|
||||
@@ -2430,7 +2436,7 @@ func TestRollingUpgradeForDaemonSetWithSecretUsingErs(t *testing.T) {
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with secret")
|
||||
@@ -2455,7 +2461,7 @@ func TestRollingUpgradeForDaemonSetWithSecretInProjectedVolumeUsingErs(t *testin
|
||||
daemonSetFuncs := GetDaemonSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, daemonSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for DaemonSet with secret in projected volume")
|
||||
@@ -2480,7 +2486,7 @@ func TestRollingUpgradeForStatefulSetWithConfigmapUsingErs(t *testing.T) {
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for StatefulSet with configmap")
|
||||
@@ -2505,7 +2511,7 @@ func TestRollingUpgradeForStatefulSetWithConfigmapInProjectedVolumeUsingErs(t *t
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for StatefulSet with configmap in projected volume")
|
||||
@@ -2530,7 +2536,7 @@ func TestRollingUpgradeForStatefulSetWithSecretUsingErs(t *testing.T) {
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for StatefulSet with secret")
|
||||
@@ -2555,7 +2561,7 @@ func TestRollingUpgradeForStatefulSetWithSecretInProjectedVolumeUsingErs(t *test
|
||||
statefulSetFuncs := GetStatefulSetRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, statefulSetFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for StatefulSet with secret in projected volume")
|
||||
@@ -2580,7 +2586,7 @@ func TestRollingUpgradeForDeploymentWithPodAnnotationsUsingErs(t *testing.T) {
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
collectors := getCollectors()
|
||||
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
err := PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
time.Sleep(5 * time.Second)
|
||||
if err != nil {
|
||||
t.Errorf("Rolling upgrade failed for Deployment with pod annotations")
|
||||
@@ -2591,7 +2597,11 @@ func TestRollingUpgradeForDeploymentWithPodAnnotationsUsingErs(t *testing.T) {
|
||||
items := deploymentFuncs.ItemsFunc(clients, config.Namespace)
|
||||
var foundPod, foundBoth bool
|
||||
for _, i := range items {
|
||||
name := util.ToObjectMeta(i).Name
|
||||
accessor, err := meta.Accessor(i)
|
||||
if err != nil {
|
||||
t.Errorf("Error getting accessor for item: %v", err)
|
||||
}
|
||||
name := accessor.GetName()
|
||||
if name == ersConfigmapWithPodAnnotations {
|
||||
containers := deploymentFuncs.ContainersFunc(i)
|
||||
updated := testutil.GetResourceSHAFromEnvVar(containers, envName)
|
||||
@@ -2627,12 +2637,12 @@ func TestFailedRollingUpgradeUsingErs(t *testing.T) {
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, ersNamespace, ersConfigmapName, "fail.stakater.com")
|
||||
config := getConfigWithAnnotations(constants.ConfigmapEnvVarPostfix, ersConfigmapName, shaData, options.ConfigmapUpdateOnChangeAnnotation)
|
||||
deploymentFuncs := GetDeploymentRollingUpgradeFuncs()
|
||||
deploymentFuncs.UpdateFunc = func(_ kube.Clients, _ string, _ interface{}) error {
|
||||
deploymentFuncs.UpdateFunc = func(_ kube.Clients, _ string, _ runtime.Object) error {
|
||||
return fmt.Errorf("error")
|
||||
}
|
||||
collectors := getCollectors()
|
||||
|
||||
_ = PerformRollingUpgrade(clients, config, deploymentFuncs, collectors)
|
||||
_ = PerformRollingUpgrade(clients, config, deploymentFuncs, collectors, nil)
|
||||
|
||||
if promtestutil.ToFloat64(collectors.Reloaded.With(labelFailed)) != 1 {
|
||||
t.Errorf("Counter was not increased")
|
||||
|
||||
110
internal/pkg/leadership/leadership.go
Normal file
110
internal/pkg/leadership/leadership.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package leadership
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/controller"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/tools/leaderelection"
|
||||
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
|
||||
coordinationv1 "k8s.io/client-go/kubernetes/typed/coordination/v1"
|
||||
)
|
||||
|
||||
const healthPort string = ":9091"
|
||||
|
||||
var (
|
||||
// Used for liveness probe
|
||||
m sync.Mutex
|
||||
healthy bool = true
|
||||
)
|
||||
|
||||
func GetNewLock(client coordinationv1.CoordinationV1Interface, lockName, podname, namespace string) *resourcelock.LeaseLock {
|
||||
return &resourcelock.LeaseLock{
|
||||
LeaseMeta: v1.ObjectMeta{
|
||||
Name: lockName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Client: client,
|
||||
LockConfig: resourcelock.ResourceLockConfig{
|
||||
Identity: podname,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// runLeaderElection runs leadership election. If an instance of the controller is the leader and stops leading it will shutdown.
|
||||
func RunLeaderElection(lock *resourcelock.LeaseLock, ctx context.Context, cancel context.CancelFunc, id string, controllers []*controller.Controller) {
|
||||
// Construct channels for the controllers to use
|
||||
var stopChannels []chan struct{}
|
||||
for i := 0; i < len(controllers); i++ {
|
||||
stop := make(chan struct{})
|
||||
stopChannels = append(stopChannels, stop)
|
||||
}
|
||||
|
||||
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
|
||||
Lock: lock,
|
||||
ReleaseOnCancel: true,
|
||||
LeaseDuration: 15 * time.Second,
|
||||
RenewDeadline: 10 * time.Second,
|
||||
RetryPeriod: 2 * time.Second,
|
||||
Callbacks: leaderelection.LeaderCallbacks{
|
||||
OnStartedLeading: func(c context.Context) {
|
||||
logrus.Info("became leader, starting controllers")
|
||||
runControllers(controllers, stopChannels)
|
||||
},
|
||||
OnStoppedLeading: func() {
|
||||
logrus.Info("no longer leader, shutting down")
|
||||
stopControllers(stopChannels)
|
||||
cancel()
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
healthy = false
|
||||
},
|
||||
OnNewLeader: func(current_id string) {
|
||||
if current_id == id {
|
||||
logrus.Info("still the leader!")
|
||||
return
|
||||
}
|
||||
logrus.Infof("new leader is %s", current_id)
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func runControllers(controllers []*controller.Controller, stopChannels []chan struct{}) {
|
||||
for i, c := range controllers {
|
||||
c := c
|
||||
go c.Run(1, stopChannels[i])
|
||||
}
|
||||
}
|
||||
|
||||
func stopControllers(stopChannels []chan struct{}) {
|
||||
for _, c := range stopChannels {
|
||||
close(c)
|
||||
}
|
||||
}
|
||||
|
||||
// Healthz serves the liveness probe endpoint. If leadership election is
|
||||
// enabled and a replica stops leading the liveness probe will fail and the
|
||||
// kubelet will restart the container.
|
||||
func Healthz() error {
|
||||
http.HandleFunc("/live", healthz)
|
||||
return http.ListenAndServe(healthPort, nil)
|
||||
}
|
||||
|
||||
func healthz(w http.ResponseWriter, req *http.Request) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
if healthy {
|
||||
if i, err := w.Write([]byte("alive")); err != nil {
|
||||
logrus.Infof("failed to write liveness response, wrote: %d bytes, got err: %s", i, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
213
internal/pkg/leadership/leadership_test.go
Normal file
213
internal/pkg/leadership/leadership_test.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package leadership
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/controller"
|
||||
"github.com/stakater/Reloader/internal/pkg/handler"
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
testutil.CreateNamespace(testutil.Namespace, testutil.Clients.KubernetesClient)
|
||||
|
||||
logrus.Infof("Running Testcases")
|
||||
retCode := m.Run()
|
||||
|
||||
testutil.DeleteNamespace(testutil.Namespace, testutil.Clients.KubernetesClient)
|
||||
|
||||
os.Exit(retCode)
|
||||
}
|
||||
|
||||
func TestHealthz(t *testing.T) {
|
||||
request, err := http.NewRequest(http.MethodGet, "/live", nil)
|
||||
if err != nil {
|
||||
t.Fatalf(("failed to create request"))
|
||||
}
|
||||
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
healthz(response, request)
|
||||
got := response.Code
|
||||
want := 200
|
||||
|
||||
if got != want {
|
||||
t.Fatalf("got: %q, want: %q", got, want)
|
||||
}
|
||||
|
||||
// Have the liveness probe serve a 500
|
||||
healthy = false
|
||||
|
||||
request, err = http.NewRequest(http.MethodGet, "/live", nil)
|
||||
if err != nil {
|
||||
t.Fatalf(("failed to create request"))
|
||||
}
|
||||
|
||||
response = httptest.NewRecorder()
|
||||
|
||||
healthz(response, request)
|
||||
got = response.Code
|
||||
want = 500
|
||||
|
||||
if got != want {
|
||||
t.Fatalf("got: %q, want: %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunLeaderElection validates that the liveness endpoint serves 500 when
|
||||
// leadership election fails
|
||||
func TestRunLeaderElection(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
|
||||
lock := GetNewLock(testutil.Clients.KubernetesClient.CoordinationV1(), constants.LockName, testutil.Pod, testutil.Namespace)
|
||||
|
||||
go RunLeaderElection(lock, ctx, cancel, testutil.Pod, []*controller.Controller{})
|
||||
|
||||
// Liveness probe should be serving OK
|
||||
request, err := http.NewRequest(http.MethodGet, "/live", nil)
|
||||
if err != nil {
|
||||
t.Fatalf(("failed to create request"))
|
||||
}
|
||||
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
healthz(response, request)
|
||||
got := response.Code
|
||||
want := 500
|
||||
|
||||
if got != want {
|
||||
t.Fatalf("got: %q, want: %q", got, want)
|
||||
}
|
||||
|
||||
// Cancel the leader election context, so leadership is released and
|
||||
// live endpoint serves 500
|
||||
cancel()
|
||||
|
||||
request, err = http.NewRequest(http.MethodGet, "/live", nil)
|
||||
if err != nil {
|
||||
t.Fatalf(("failed to create request"))
|
||||
}
|
||||
|
||||
response = httptest.NewRecorder()
|
||||
|
||||
healthz(response, request)
|
||||
got = response.Code
|
||||
want = 500
|
||||
|
||||
if got != want {
|
||||
t.Fatalf("got: %q, want: %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunLeaderElectionWithControllers tests that leadership election works
|
||||
// wiht real controllers and that on context cancellation the controllers stop
|
||||
// running.
|
||||
func TestRunLeaderElectionWithControllers(t *testing.T) {
|
||||
t.Logf("Creating controller")
|
||||
var controllers []*controller.Controller
|
||||
for k := range kube.ResourceMap {
|
||||
c, err := controller.NewController(testutil.Clients.KubernetesClient, k, testutil.Namespace, []string{}, map[string]string{}, metrics.NewCollectors())
|
||||
if err != nil {
|
||||
logrus.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
controllers = append(controllers, c)
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
lock := GetNewLock(testutil.Clients.KubernetesClient.CoordinationV1(), fmt.Sprintf("%s-%d", constants.LockName, 1), testutil.Pod, testutil.Namespace)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
|
||||
// Start running leadership election, this also starts the controllers
|
||||
go RunLeaderElection(lock, ctx, cancel, testutil.Pod, controllers)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// Create some stuff and do a thing
|
||||
configmapName := testutil.ConfigmapNamePrefix + "-update-" + testutil.RandSeq(5)
|
||||
configmapClient, err := testutil.CreateConfigMap(testutil.Clients.KubernetesClient, testutil.Namespace, configmapName, "www.google.com")
|
||||
if err != nil {
|
||||
t.Fatalf("Error while creating the configmap %v", err)
|
||||
}
|
||||
|
||||
// Creating deployment
|
||||
_, err = testutil.CreateDeployment(testutil.Clients.KubernetesClient, configmapName, testutil.Namespace, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Error in deployment creation: %v", err)
|
||||
}
|
||||
|
||||
// Updating configmap for first time
|
||||
updateErr := testutil.UpdateConfigMap(configmapClient, testutil.Namespace, configmapName, "", "www.stakater.com")
|
||||
if updateErr != nil {
|
||||
t.Fatalf("Configmap was not updated")
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// Verifying deployment update
|
||||
logrus.Infof("Verifying pod envvars has been created")
|
||||
shaData := testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, testutil.Namespace, configmapName, "www.stakater.com")
|
||||
config := util.Config{
|
||||
Namespace: testutil.Namespace,
|
||||
ResourceName: configmapName,
|
||||
SHAValue: shaData,
|
||||
Annotation: options.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs := handler.GetDeploymentRollingUpgradeFuncs()
|
||||
updated := testutil.VerifyResourceEnvVarUpdate(testutil.Clients, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if !updated {
|
||||
t.Fatalf("Deployment was not updated")
|
||||
}
|
||||
time.Sleep(testutil.SleepDuration)
|
||||
|
||||
// Cancel the leader election context, so leadership is released
|
||||
logrus.Info("shutting down controller from test")
|
||||
cancel()
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// Updating configmap again
|
||||
updateErr = testutil.UpdateConfigMap(configmapClient, testutil.Namespace, configmapName, "", "www.stakater.com/new")
|
||||
if updateErr != nil {
|
||||
t.Fatalf("Configmap was not updated")
|
||||
}
|
||||
|
||||
// Verifying that the deployment was not updated as leadership has been lost
|
||||
logrus.Infof("Verifying pod envvars has not been updated")
|
||||
shaData = testutil.ConvertResourceToSHA(testutil.ConfigmapResourceType, testutil.Namespace, configmapName, "www.stakater.com/new")
|
||||
config = util.Config{
|
||||
Namespace: testutil.Namespace,
|
||||
ResourceName: configmapName,
|
||||
SHAValue: shaData,
|
||||
Annotation: options.ConfigmapUpdateOnChangeAnnotation,
|
||||
}
|
||||
deploymentFuncs = handler.GetDeploymentRollingUpgradeFuncs()
|
||||
updated = testutil.VerifyResourceEnvVarUpdate(testutil.Clients, config, constants.ConfigmapEnvVarPostfix, deploymentFuncs)
|
||||
if updated {
|
||||
t.Fatalf("Deployment was updated")
|
||||
}
|
||||
|
||||
// Deleting deployment
|
||||
err = testutil.DeleteDeployment(testutil.Clients.KubernetesClient, testutil.Namespace, configmapName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the deployment %v", err)
|
||||
}
|
||||
|
||||
// Deleting configmap
|
||||
err = testutil.DeleteConfigMap(testutil.Clients.KubernetesClient, testutil.Namespace, configmapName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while deleting the configmap %v", err)
|
||||
}
|
||||
time.Sleep(testutil.SleepDuration)
|
||||
}
|
||||
@@ -25,4 +25,6 @@ var (
|
||||
ReloadStrategy = constants.EnvVarsReloadStrategy
|
||||
// ReloadOnCreate Adds support to watch create events
|
||||
ReloadOnCreate = "false"
|
||||
// EnableHA adds support for running multiple replicas via leadership election
|
||||
EnableHA = false
|
||||
)
|
||||
|
||||
@@ -16,11 +16,13 @@ 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/metrics"
|
||||
"github.com/stakater/Reloader/internal/pkg/options"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
"github.com/stakater/Reloader/pkg/kube"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
core_v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
@@ -34,6 +36,19 @@ var (
|
||||
SecretResourceType = "secrets"
|
||||
)
|
||||
|
||||
var (
|
||||
Clients = kube.GetClients()
|
||||
Pod = "test-reloader-" + RandSeq(5)
|
||||
Namespace = "test-reloader-" + RandSeq(5)
|
||||
ConfigmapNamePrefix = "testconfigmap-reloader"
|
||||
SecretNamePrefix = "testsecret-reloader"
|
||||
Data = "dGVzdFNlY3JldEVuY29kaW5nRm9yUmVsb2FkZXI="
|
||||
NewData = "dGVzdE5ld1NlY3JldEVuY29kaW5nRm9yUmVsb2FkZXI="
|
||||
UpdatedData = "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy"
|
||||
Collectors = metrics.NewCollectors()
|
||||
SleepDuration = 3 * time.Second
|
||||
)
|
||||
|
||||
// CreateNamespace creates namespace for testing
|
||||
func CreateNamespace(namespace string, client kubernetes.Interface) {
|
||||
_, err := client.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}, metav1.CreateOptions{})
|
||||
@@ -600,7 +615,7 @@ func GetResourceSHAFromAnnotation(podAnnotations map[string]string) string {
|
||||
return last.Hash
|
||||
}
|
||||
|
||||
//ConvertResourceToSHA generates SHA from secret or configmap data
|
||||
// ConvertResourceToSHA generates SHA from secret or configmap data
|
||||
func ConvertResourceToSHA(resourceType string, namespace string, resourceName string, data string) string {
|
||||
values := []string{}
|
||||
if resourceType == SecretResourceType {
|
||||
@@ -835,10 +850,15 @@ func VerifyResourceEnvVarUpdate(clients kube.Clients, config util.Config, envVar
|
||||
items := upgradeFuncs.ItemsFunc(clients, config.Namespace)
|
||||
for _, i := range items {
|
||||
containers := upgradeFuncs.ContainersFunc(i)
|
||||
accessor, err := meta.Accessor(i)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
annotations := accessor.GetAnnotations()
|
||||
// match statefulsets with the correct annotation
|
||||
annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation]
|
||||
searchAnnotationValue := util.ToObjectMeta(i).Annotations[options.AutoSearchAnnotation]
|
||||
reloaderEnabledValue := util.ToObjectMeta(i).Annotations[options.ReloaderAutoAnnotation]
|
||||
annotationValue := annotations[config.Annotation]
|
||||
searchAnnotationValue := annotations[options.AutoSearchAnnotation]
|
||||
reloaderEnabledValue := annotations[options.ReloaderAutoAnnotation]
|
||||
reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue)
|
||||
matches := false
|
||||
if err == nil && reloaderEnabled {
|
||||
@@ -874,10 +894,15 @@ func VerifyResourceAnnotationUpdate(clients kube.Clients, config util.Config, up
|
||||
items := upgradeFuncs.ItemsFunc(clients, config.Namespace)
|
||||
for _, i := range items {
|
||||
podAnnotations := upgradeFuncs.PodAnnotationsFunc(i)
|
||||
accessor, err := meta.Accessor(i)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
annotations := accessor.GetAnnotations()
|
||||
// match statefulsets with the correct annotation
|
||||
annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation]
|
||||
searchAnnotationValue := util.ToObjectMeta(i).Annotations[options.AutoSearchAnnotation]
|
||||
reloaderEnabledValue := util.ToObjectMeta(i).Annotations[options.ReloaderAutoAnnotation]
|
||||
annotationValue := annotations[config.Annotation]
|
||||
searchAnnotationValue := annotations[options.AutoSearchAnnotation]
|
||||
reloaderEnabledValue := annotations[options.ReloaderAutoAnnotation]
|
||||
reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue)
|
||||
matches := false
|
||||
if err == nil && reloaderEnabled {
|
||||
|
||||
@@ -54,6 +54,8 @@ func GetSHAfromSecret(data map[string][]byte) string {
|
||||
|
||||
type List []string
|
||||
|
||||
type Map map[string]string
|
||||
|
||||
func (l *List) Contains(s string) bool {
|
||||
for _, v := range *l {
|
||||
if v == s {
|
||||
|
||||
31
okteto.yml
31
okteto.yml
@@ -1,14 +1,17 @@
|
||||
name: reloader-reloader
|
||||
image: okteto/golang:1
|
||||
command: bash
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- SYS_PTRACE
|
||||
volumes:
|
||||
- /go/pkg/
|
||||
- /root/.cache/go-build/
|
||||
sync:
|
||||
- .:/app
|
||||
forward:
|
||||
- 2345:2345
|
||||
dev:
|
||||
reloader-reloader:
|
||||
image: okteto/golang:1
|
||||
command: bash
|
||||
volumes:
|
||||
- /go/pkg/
|
||||
- /root/.cache/go-build/
|
||||
sync:
|
||||
- .:/app
|
||||
forward:
|
||||
- 2345:2345
|
||||
workdir: /app
|
||||
autocreate: true
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- SYS_PTRACE
|
||||
|
||||
Reference in New Issue
Block a user