From 900528164e13785795a1c81b3832030edecff6ba Mon Sep 17 00:00:00 2001 From: "James E. Blair" Date: Thu, 15 Jul 2021 13:45:15 -0700 Subject: [PATCH] Fix config update detection We are supposed to update zuul/nodepool when the relevant secrets are updated. We do that by subscribing to changes on all secrets in the system, then check to see if they are ones that we're watching and if so, run the appropriate operator methods. We only updated the list of secrets to watch on startup, which means that from a clean start where a zuul was added, we would not add the new secrets to our list. This change updates the list after every time that the zuul resource is created or updated. Change-Id: Ib6191367eb2596eba560b9c570140f33866c005f --- zuul_operator/operator.py | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/zuul_operator/operator.py b/zuul_operator/operator.py index c80ce80..de9c547 100644 --- a/zuul_operator/operator.py +++ b/zuul_operator/operator.py @@ -26,17 +26,17 @@ ConfigResource = collections.namedtuple('ConfigResource', [ 'attr', 'namespace', 'zuul_name', 'resource_name']) -@kopf.on.startup() -def startup(memo, **kwargs): +def memoize_secrets(memo, logger): # (zuul_namespace, zuul) -> list of resources - memo.config_resources = {} + memo.config_resources.clear() + new_resources = {} # lookup all zuuls and update configmaps api = pykube.HTTPClient(pykube.KubeConfig.from_env()) for namespace in objects.Namespace.objects(api): for zuul in objects.ZuulObject.objects(api).filter( namespace=namespace.name): - resources = memo.config_resources.\ + resources = new_resources.\ setdefault((namespace.name, zuul.name), []) # Zuul tenant config secret = zuul.obj['spec']['scheduler']['config']['secretName'] @@ -49,6 +49,22 @@ def startup(memo, **kwargs): res = ConfigResource('spec.launcher.config.secretName', namespace.name, zuul.name, secret) resources.append(res) + # Mutate the global instance + memo.config_resources.clear() + memo.config_resources.update(new_resources) + + +@kopf.on.startup() +def startup(memo, logger, **kwargs): + # Operator handlers (like this one) get a single global memo + # object; resource handlers (like update) get a memo object for + # that specific resource with items shallow-copied from the global + # memo. + # + # Initialize a dictionary here that we will mutate (but never + # overwrite) in all the handlers. + memo.config_resources = {} + memoize_secrets(memo, logger) @kopf.on.update('secrets') @@ -74,7 +90,7 @@ def update_secret(name, namespace, logger, memo, new, **kwargs): @kopf.on.create('zuuls', backoff=10) -def create_fn(spec, name, namespace, logger, **kwargs): +def create_fn(spec, name, namespace, logger, memo, **kwargs): logger.info(f"Create zuul {namespace}/{name}") zuul = Zuul(namespace, name, logger, spec) @@ -95,12 +111,13 @@ def create_fn(spec, name, namespace, logger, **kwargs): zuul.write_zuul_conf() zuul.create_zuul() + memoize_secrets(memo, logger) # We can set a status with something like: # return {'message': 'hello world'} @kopf.on.update('zuuls', backoff=10) -def update_fn(name, namespace, logger, old, new, **kwargs): +def update_fn(name, namespace, logger, old, new, memo, **kwargs): logger.info(f"Update zuul {namespace}/{name}") old = old['spec'] @@ -145,6 +162,8 @@ def update_fn(name, namespace, logger, old, new, **kwargs): if spec_changed: zuul.create_zuul() + memoize_secrets(memo, logger) + class ZuulOperator: def run(self):