Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ For only sync in this namespaces:
Sync all namespaces excludes this namespaces:
`synator/exclude-namespaces='kube-system,kube-node-lease'`

# Reload deployment when config upgraded
=======
![secret.yaml](https://miro.medium.com/max/2400/1*UH4iTu3Gg6DkofHyX2KDHg.png)

## Reload pod when config upgraded
Add annotation `synator/reload: "secret:example"` to pod or deployment template
Add annotation `synator/reload: "secret:example"` to deployment template
When secret example updated busybox pod will reload

Note: For multiple secrte or configmap:
Expand Down
8 changes: 6 additions & 2 deletions deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ metadata:
name: synator
rules:
- apiGroups: [""]
resources: ["secrets", "configmaps"]
resources: ["secrets", "configmaps", "deployments"]
verbs: ["*"]
- apiGroups: [events.k8s.io]
resources: [events]
Expand All @@ -20,7 +20,11 @@ rules:
resources: [events]
verbs: [create]
- apiGroups: [""]
resources: ["namespaces", "pods", "replicasets", "namespaces/status"]
resources:
["namespaces", "pods", "replicasets", "deployments", "namespaces/status"]
verbs: ["*"]
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["*"]
---
kind: ClusterRoleBinding
Expand Down
78 changes: 50 additions & 28 deletions handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def update_secret(body, meta, spec, status, old, new, diff, **kwargs):

secret = api.read_namespaced_secret(meta.name, meta.namespace)
secret.metadata.annotations.pop('synator/sync')
secret.metadata.annotations.pop('field.cattle.io/projectId')
secret.metadata.resource_version = None
secret.metadata.uid = None
for ns in parse_target_namespaces(meta, namespaces):
Expand All @@ -42,6 +43,7 @@ def updateConfigMap(body, meta, spec, status, old, new, diff, **kwargs):

cfg = api.read_namespaced_config_map(meta.name, meta.namespace)
cfg.metadata.annotations.pop('synator/sync')
cfg.metadata.annotations.pop('field.cattle.io/projectId')
cfg.metadata.resource_version = None
cfg.metadata.uid = None
for ns in parse_target_namespaces(meta, namespaces):
Expand Down Expand Up @@ -98,6 +100,7 @@ def newNamespace(spec, name, meta, logger, **kwargs):
# Check secret have annotation
if secret.metadata.annotations and secret.metadata.annotations.get("synator/sync") == "yes":
secret.metadata.annotations.pop('synator/sync')
secret.metadata.annotations.pop('field.cattle.io/projectId')
secret.metadata.resource_version = None
secret.metadata.uid = None
for ns in parse_target_namespaces(secret.metadata, [name]):
Expand All @@ -114,35 +117,54 @@ def newNamespace(spec, name, meta, logger, **kwargs):
print("Exception when calling CoreV1Api->list_secret_for_all_namespaces: %s\n" % e)


# Reload Pod when update configmap or secret
# Reload deployment when update configmap or secret

@kopf.on.update('', 'v1', 'configmaps', when=watch_namespace)
def reload_pod_config(body, meta, spec, status, old, new, diff, **kwargs):
# Get namespace
ns = meta.namespace
api = kubernetes.client.CoreV1Api()
pods = api.list_namespaced_pod(ns)
print(ns, meta.name)
for pod in pods.items:
# Find which pods use this secrets
if pod.metadata.annotations and pod.metadata.annotations.get('synator/reload'):
if any('configmap:' + meta.name in s for s in pod.metadata.annotations.get('synator/reload').split(',')):
# Reload pod
api.delete_namespaced_pod(
pod.metadata.name, pod.metadata.namespace)

def reload_deployment_config(body, meta, spec, status, old, new, diff, logger, **kwargs):
reload_deployments_sync(meta, 'configmap', logger)

@kopf.on.update('', 'v1', 'secrets', when=watch_namespace)
def reload_pod_secret(body, meta, spec, status, old, new, diff, **kwargs):
# Get namespace
ns = meta.namespace
api = kubernetes.client.CoreV1Api()
pods = api.list_namespaced_pod(ns)
print(ns, meta.name)
for pod in pods.items:
# Find which pods use this secrets
if pod.metadata.annotations and pod.metadata.annotations.get('synator/reload'):
if any('secret:' + meta.name in s for s in pod.metadata.annotations.get('synator/reload').split(',')):
# Reload pod
api.delete_namespaced_pod(
pod.metadata.name, pod.metadata.namespace)
def reload_deployment_secret(body, meta, spec, status, old, new, diff, logger, **kwargs):
reload_deployments_sync(meta, 'secret', logger)

def reload_deployments_sync(meta, secretOrConfigmap, logger):
try:
# Get namespace
ns = meta.namespace
api = kubernetes.client.AppsV1Api()
deployments = api.list_namespaced_deployment(ns)
configSearch = secretOrConfigmap + ':' + meta.name

logger.info(f"NS: %s Name: %s Deployments %s", ns, configSearch, str(len(deployments.items)))

for deployment in deployments.items:
annotations = deployment.spec.template.metadata.annotations
syncReloads = []
if annotations and annotations.get('synator/reload'):
syncReloads = annotations.get('synator/reload').split(',')

if any(configSearch in s for s in syncReloads):
# Reload deployment
update_deployment(api, deployment, logger)
except kubernetes.client.rest.ApiException as e:
print("Exception when calling AppsV1Api: %s\n" % e)

def update_deployment(api, deployment, logger):
# Update revision
revision = deployment.spec.template.metadata.annotations.get('synator/revision')
if revision is None:
revision = 1
else:
revision = int(revision) + 1

deployment.spec.template.metadata.annotations['synator/revision'] = str(revision)

# Update the deployment
api_response = api.patch_namespaced_deployment(
name=deployment.metadata.name,
namespace=deployment.metadata.namespace,
body=deployment)

# print("Deployment updated. status='%s'" % str(api_response.status))

logger.info(f"Deployment %s updated revision %s", deployment.metadata.name, str(revision))