-
-
Save WalBeh/2f9f2115961a7fce8ec5f57ecf3ccb65 to your computer and use it in GitHub Desktop.
k8s update deployment and cronjob
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| """ Update the backup image in the cratedDB namespaces. | |
| The script iterates over all cratedbs in a k8s context and updates tag on the deployment and cronjob | |
| using the backup image. | |
| The script can be run standlone/locally, or on-demand in the cluster via CI/CD. Runtime | |
| behaviour and configuration is controlled via environment variables. | |
| The k8s context need to match the cluster names in your kubeconfig file. | |
| """ | |
| # https://pip.wtf | |
| def pip_wtf(command): | |
| """Setup python module.""" | |
| import os, os.path, sys | |
| t = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".pip_wtf." + os.path.basename(__file__)) | |
| sys.path = [p for p in sys.path if "-packages" not in p] + [t] | |
| os.environ["PATH"] += os.pathsep + t + os.path.sep + "bin" | |
| os.environ["PYTHONPATH"] = os.pathsep.join(sys.path) | |
| if os.path.exists(t): return | |
| os.system(" ".join([sys.executable, "-m", "pip", "install", "-t", t, command])) | |
| import sys | |
| pip_wtf('kubernetes structlog') | |
| from kubernetes import client, config, utils | |
| from kubernetes.client.rest import ApiException | |
| from distutils.util import strtobool | |
| import os | |
| import logging | |
| import structlog | |
| # Optional environment settings | |
| CONTEXTS = os.getenv('KUBE_CONTEXTS', 'aks1-eastus-dev') | |
| DRY_RUN = strtobool(os.getenv('DRY_RUN', True)) | |
| IMAGE_NAME = os.getenv('IMAGE_NAME', 'cloud.registry.cr8.net/crate/cloud-cluster-backup') | |
| IGNORED_NAMESPACES = os.getenv('IGNORED_NAMESPACES', 'templates, cloud-app') | |
| LOGLEVEL = os.environ.get("LOG_LEVEL", "INFO").upper() | |
| ONLY_NAMESPACE = os.getenv('ONLY_NAMESPACE', "06410cd8-1e4c-462f-92ca-9a0a5864b6b0") | |
| TAG = os.getenv('TAG', '0.30.1') | |
| # Constants | |
| API_GROUP = "cloud.crate.io" | |
| CJ_NAME = "create-snapshot-" | |
| DEPLOYMENT_NAME = "backup-metrics-" | |
| RESOURCE_CRATEDB = "cratedbs" | |
| # Logging Setup | |
| LOG_LEVEL = getattr(logging, LOGLEVEL) | |
| structlog.configure(wrapper_class=structlog.make_filtering_bound_logger(LOG_LEVEL)) | |
| logger = structlog.get_logger() | |
| # Log relevant environment settings during startup | |
| logger.info("Updating backup image to tag: %s", TAG) | |
| if DRY_RUN: logger.info("Dry Run: %s", DRY_RUN) | |
| if IGNORED_NAMESPACES: logger.info("IGNORED_NAMESPACES: %s", IGNORED_NAMESPACES) | |
| if ONLY_NAMESPACE: logger.info("ONLY_NAMESPACE: %s", ONLY_NAMESPACE) | |
| def update_deployment(api, deployment, image_name, tag, dry_run): | |
| old_tag = deployment.spec.template.spec.containers[0].image | |
| deployment.spec.template.spec.containers[0].image = f"{image_name}:{tag}" | |
| if old_tag == f"{image_name}:{tag}": | |
| logger.info(f" Deployment Image already up-to-date: {old_tag}") | |
| else: | |
| if not dry_run: | |
| api.replace_namespaced_deployment(bkp_depl, namespace.metadata.name, deployment) | |
| logger.info(f" Updated Deployment - {deployment.metadata.name}") | |
| else: | |
| logger.info(f" Dry Run: Deployment would be updated - {deployment.metadata.name}") | |
| def update_cronjob(cj, cronjob, image_name, tag, dry_run): | |
| old_tag = cronjob.spec.job_template.spec.template.spec.containers[0].image | |
| if old_tag == f"{image_name}:{tag}": | |
| logger.info(f" Cronjob Image already up-to-date: {old_tag}") | |
| else: | |
| cronjob.spec.job_template.spec.template.spec.containers[0].image = f"{image_name}:{tag}" | |
| if not dry_run: | |
| cj.replace_namespaced_cron_job(bkp_cj, namespace.metadata.name, cronjob) | |
| logger.info(f" Updated Cronjob updated - {cronjob.metadata.name}") | |
| else: | |
| logger.info(f" Dry Run: Cronjob would be updated - {cronjob.metadata.name}") | |
| # switch to a specific k8s context provided by an environment variable | |
| # multiple contexts can be provided as a space separated list | |
| for context in CONTEXTS.split(" "): | |
| logger.warning("Kubernetes Context: %s", context) | |
| config.load_kube_config(context=context) | |
| # Setup the k8s client | |
| crd = client.CustomObjectsApi() | |
| core_api = client.CoreV1Api() | |
| api = client.AppsV1Api() | |
| cj = client.BatchV1Api() | |
| cratedbs = crd.list_cluster_custom_object(API_GROUP, "v1", RESOURCE_CRATEDB) | |
| # Loop over all cratedbs in the k8s context | |
| for cratedb in cratedbs['items']: | |
| # Mostly a safety measure, this will ignore the specified namespaces | |
| # but they should not have any crateDB CRDs | |
| if cratedb['metadata']['namespace'] in IGNORED_NAMESPACES: | |
| logger.warning("Ignoring namespace: %s", cratedb['metadata']['namespace']) | |
| continue | |
| # Mostly for testing purposes, this will only update the specified namespace | |
| if ONLY_NAMESPACE: | |
| if cratedb['metadata']['namespace'] != ONLY_NAMESPACE: | |
| logger.warning("Skipping namespace: %s", cratedb['metadata']['namespace']) | |
| continue | |
| logger.info("// namespace: %s",cratedb["metadata"]["namespace"]) | |
| try: | |
| logger.warning(" cratedb: %s %s", cratedb["metadata"]["name"], cratedb["spec"]["cluster"]["name"]) | |
| # Get the current deployment | |
| namespace = core_api.read_namespace(cratedb['metadata']['namespace']) | |
| bkp_depl = DEPLOYMENT_NAME + cratedb["metadata"]["name"] | |
| deployment = api.read_namespaced_deployment(bkp_depl , namespace.metadata.name) | |
| logger.info(" current Deployment: %s, %s", deployment.metadata.name, deployment.spec.template.spec.containers[0].image.split(":")[-1]) | |
| update_deployment(api, deployment, IMAGE_NAME, TAG, DRY_RUN) | |
| # Now also update the responding cronjob | |
| bkp_cj = CJ_NAME + cratedb["metadata"]["name"] | |
| cronjob = cj.read_namespaced_cron_job(bkp_cj, namespace.metadata.name) | |
| logger.info(" current Cronjob: %s %s", cronjob.metadata.name, cronjob.spec.job_template.spec.template.spec.containers[0].image.split(":")[-1]) | |
| #ic(cronjob.spec.job_template.spec.template.spec.containers[0].image) | |
| update_cronjob(cj, cronjob, IMAGE_NAME, TAG, DRY_RUN) | |
| except ApiException as e: | |
| if e.status == 404: | |
| logger.error(" backup-metrics deployment not found!") | |
| else: | |
| raise |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment