diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..997ef38 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + diff --git a/README.md b/README.md index 75b5077..0f1d30b 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,14 @@ The following environment variables can be set: Name | description | default --- | --- | --- +DOCKER_CERTIFICATE_SECRET | You **must** provide a certificate to enable TLS between the docker daemon and the registry and create a secret from it, this variable is the name of the secret | None NAMESPACE | The namespace in which the resources should be created. This should be the same namespace as where the container is running | default SECONDS_BETWEEN_STREAMS | Time to sleep between calls to the API. The operator will occasionally lose connection or else fail to run if the Custom Resource Definition does not exist. | 30 HOSTESS_DOCKER_REGISTRY | The docker registry where mirror-hostess is to be pulled from. | docker.io HOSTESS_DOCKER_IMAGE | The name of the docker image for mirror-hostess. | ocadotechnology/mirror-hostess HOSTESS_DOCKER_TAG | The tag for the mirror-hostess docker image. | 1.1.0 +IMAGE_PULL_SECRETS | (Optional) Secret to pull images from the upstream registry | None +CA_CERTIFICATE_BUNDLE | (Optional) Certificate bundle for the registry host | None ## Usage In order to have the operator deploy a new mirror, the cluster needs to have the custom resource defined: diff --git a/mirroroperator/operator.py b/mirroroperator/operator.py index d7d8019..ba7c6eb 100644 --- a/mirroroperator/operator.py +++ b/mirroroperator/operator.py @@ -24,9 +24,11 @@ def __init__(self, env_vars): hostess_docker_image (used in RegistryMirror), hostess_docker_tag (used in RegistryMirror), image_pull_secrets(used in RegistryMirror, optional), - secret_name(optional), - cert_name(optional) + docker_certificate_secret(used in RegistryMirror), + ca_certificate_bundle(optional) """ + if not env_vars.get("docker_certificate_secret"): + raise TypeError("Missing docker certificate secret") self.registry_mirror_vars = env_vars kubernetes.config.load_incluster_config() self.crd_api = kubernetes.client.ExtensionsV1beta1Api() @@ -62,10 +64,10 @@ def watch_registry_mirrors(self): hostess_docker_tag=os.environ.get("HOSTESS_DOCKER_TAG", "1.1.0"), # optional in V1PodSpec secrets split with comma image_pull_secrets=os.environ.get("IMAGE_PULL_SECRETS"), - # get secret name: - secret_name=os.environ.get("SECRET_NAME"), - # cert_name - needed in clusters - cert_name=os.environ.get("CERT_NAME"), + # get the docker certificate: + docker_certificate_secret=os.environ.get("DOCKER_CERTIFICATE_SECRET"), + # get ca certificate + ca_certificate_bundle=os.environ.get("CA_CERTIFICATE_BUNDLE"), ) operator = MirrorOperator(env_vars) diff --git a/mirroroperator/registrymirror.py b/mirroroperator/registrymirror.py index 3be62cc..0c4902a 100644 --- a/mirroroperator/registrymirror.py +++ b/mirroroperator/registrymirror.py @@ -12,12 +12,14 @@ class RegistryMirror(object): def __init__(self, event_type, namespace, hostess_docker_registry, - hostess_docker_image, hostess_docker_tag, **kwargs): + hostess_docker_image, hostess_docker_tag, + docker_certificate_secret, **kwargs): self.event_type = event_type self.namespace = namespace self.hostess_docker_registry = hostess_docker_registry self.hostess_docker_image = hostess_docker_image self.hostess_docker_tag = hostess_docker_tag + self.docker_certificate_secret = docker_certificate_secret self.kind = kwargs.get("kind") self.name = kwargs.get("metadata", {}).get("name") self.uid = kwargs.get("metadata", {}).get("uid") @@ -25,10 +27,10 @@ def __init__(self, event_type, namespace, hostess_docker_registry, self.daemon_set_name = self.full_name + "-utils" self.apiVersion = kwargs.get("apiVersion") self.upstreamUrl = kwargs.get("spec", {}).get("upstreamUrl") - self.credentials_secret_name = kwargs.get("spec", {}).get("credentialsSecret") + self.credentials_secret_name = kwargs.get( + "spec", {}).get("credentialsSecret") self.image_pull_secrets = kwargs["image_pull_secrets"] or "" - self.secret_name = kwargs["secret_name"] - self.cert_name = kwargs["cert_name"] + self.ca_certificate_bundle = kwargs["ca_certificate_bundle"] self.labels = { "app": "docker-registry", @@ -83,8 +85,8 @@ def apply(self): self.update_daemon_set(daemon_set) def run_action_and_parse_error(self, func, *args, **kwargs): - """ - Helper method to avoid try/excepts all over the place + does the exception handling and parsing + """ Helper method to avoid try/excepts all over the place + does + the exception handling and parsing. (Kubernetes python client tends to just dump the details in .body) Args: func: A function which can raise ApiException. @@ -101,7 +103,9 @@ def run_action_and_parse_error(self, func, *args, **kwargs): try: json_error = json.loads(api_exception.body) code = HTTPStatus(int(json_error['code'])) - LOGGER.exception("API returned status: %s, msg: %s, method: %s", code, json_error['message'], func) + LOGGER.exception( + "API returned status: %s, msg: %s, method: %s", + code, json_error['message'], func) except json.decoder.JSONDecodeError as e: LOGGER.error("Decoder exception loading error msg: %s;" @@ -124,23 +128,34 @@ def generate_daemon_set(self, daemon_set): client.V1Container( name="mirror-hostess", env=[ - client.V1EnvVar(name="LOCK_FILE", - value="/var/lock/hostess/mirror-hostess"), - client.V1EnvVar(name="SERVICE_NAME", - value=self.full_name), - client.V1EnvVar(name="SERVICE_NAMESPACE", - value=self.namespace), - client.V1EnvVar(name="SHADOW_FQDN", - value="mirror-"+self.upstreamUrl), - client.V1EnvVar(name="HOSTS_FILE", - value="/etc/hosts_from_host"), - client.V1EnvVar(name="HOSTS_FILE_BACKUP", - value="/etc/hosts.backup/hosts") + client.V1EnvVar( + name="LOCK_FILE", + value="/var/lock/hostess/mirror-hostess"), + client.V1EnvVar( + name="SERVICE_NAME", + value=self.full_name), + client.V1EnvVar( + name="SERVICE_NAMESPACE", + value=self.namespace), + client.V1EnvVar( + name="SHADOW_FQDN", + value="mirror-"+self.upstreamUrl), + client.V1EnvVar( + name="HOSTS_FILE", + value="/etc/hosts_from_host"), + client.V1EnvVar( + name="HOSTS_FILE_BACKUP", + value="/etc/hosts.backup/hosts") ], - image="{}/{}:{}".format(self.hostess_docker_registry, self.hostess_docker_image, self.hostess_docker_tag), + image="{}/{}:{}".format( + self.hostess_docker_registry, + self.hostess_docker_image, + self.hostess_docker_tag), image_pull_policy="Always", resources=client.V1ResourceRequirements( - requests={"memory": "32Mi", "cpu": "0.001"}, + requests={ + "memory": "32Mi", "cpu": "0.001" + }, limits={"memory": "128Mi", "cpu": "0.1"}, ), volume_mounts=[ @@ -160,7 +175,9 @@ def generate_daemon_set(self, daemon_set): ), client.V1Container( name="certificate-installation", - args=["cp /source/tls.crt /target/tls.crt; while :; do sleep 2073600; done"], + args=[ + "cp /source/tls.crt /target/tls.crt; while :; do sleep 2073600; done" + ], command=[ "/bin/sh", "-c", @@ -214,7 +231,7 @@ def generate_daemon_set(self, daemon_set): client.V1Volume( name="tls", secret=client.V1SecretVolumeSource( - secret_name=self.secret_name + secret_name=self.docker_certificate_secret ) ) ] @@ -313,7 +330,9 @@ def handle_secrets(self, keypair): return keypair def generate_stateful_set(self, stateful_set): - keypair = client.V1EnvVar(name="REGISTRY_PROXY_REMOTEURL", value="https://" + self.upstreamUrl) + keypair = client.V1EnvVar( + name="REGISTRY_PROXY_REMOTEURL", + value="https://" + self.upstreamUrl) if self.credentials_secret_name: keypair = self.handle_secrets(keypair) @@ -336,22 +355,41 @@ def generate_stateful_set(self, stateful_set): pod_labels = {'component': 'registry'} pod_labels.update(self.labels) volumes = [] - if self.cert_name: + if self.ca_certificate_bundle: volumes = [ client.V1Volume( - name=self.cert_name, + name=self.ca_certificate_bundle, config_map=client.V1ConfigMapVolumeSource( - name=self.cert_name + name=self.ca_certificate_bundle ) ) ] - if self.secret_name: - volumes.append( - client.V1Volume( - name="tls", - secret=client.V1SecretVolumeSource( - secret_name=self.secret_name - ), + volumes.append( + client.V1Volume( + name="tls", + secret=client.V1SecretVolumeSource( + secret_name=self.docker_certificate_secret + ), + ) + ) + + volumes_to_mount = [ + client.V1VolumeMount( + name="image-store", + mount_path="/var/lib/registry" + ), + client.V1VolumeMount( + name="tls", + mount_path="/etc/registry-certs", + read_only=True + ) + ] + if self.ca_certificate_bundle: + volumes_to_mount.append( + client.V1VolumeMount( + name=self.ca_certificate_bundle, + mount_path="/etc/ssl/certs", + read_only=True ) ) stateful_set.spec.template = client.V1PodTemplateSpec( @@ -411,31 +449,14 @@ def generate_stateful_set(self, stateful_set): limits={"cpu": "0.5", "memory": "500Mi"} ), - volume_mounts=[ - client.V1VolumeMount( - name="image-store", - mount_path="/var/lib/registry" - ), - client.V1VolumeMount( - name=self.cert_name, - mount_path="/etc/ssl/certs", - read_only=True - ), - client.V1VolumeMount( - name="tls", - mount_path="/etc/registry-certs", - read_only=True - ) - ], + volume_mounts=volumes_to_mount, ) ], termination_grace_period_seconds=10, - volumes=volumes or None, + volumes=volumes, ) ) - stateful_set.spec.update_strategy = client.V1beta1StatefulSetUpdateStrategy( - type="RollingUpdate", - ) + stateful_set.spec.update_strategy = client.V1beta1StatefulSetUpdateStrategy(type="RollingUpdate",) return stateful_set def update_services(self, service, service_headless): @@ -498,8 +519,11 @@ def update_stateful_set(self, stateful_set): ) if not stateful_set: stateful_set = self.generate_stateful_set(empty_stateful_set) - self.run_action_and_parse_error(self.apps_api.create_namespaced_stateful_set, - self.namespace, stateful_set) + self.run_action_and_parse_error( + self.apps_api.create_namespaced_stateful_set, + self.namespace, + stateful_set + ) LOGGER.info("Stateful set created") else: stateful_set = self.generate_stateful_set(stateful_set) diff --git a/tests/test_operator.py b/tests/test_operator.py index d9ebfa9..f876c39 100644 --- a/tests/test_operator.py +++ b/tests/test_operator.py @@ -30,8 +30,8 @@ def setUp(self): "hostess_docker_image": "ocadotechnology/mirror-hostess", "hostess_docker_tag": None, "image_pull_secrets": None, - "secret_name": None, - "cert_name": None, + "docker_certificate_secret": VALID_SECRET, + "ca_certificate_bundle": None, } self.operator = MirrorOperator(env_var_dict) diff --git a/tests/test_regmirror.py b/tests/test_regmirror.py index ae53ca1..fce3503 100644 --- a/tests/test_regmirror.py +++ b/tests/test_regmirror.py @@ -1,9 +1,13 @@ from mirroroperator.registrymirror import RegistryMirror from tests.kubernetes_test_case import KubernetesTestCase -from tests.kubernetes_mock_responses import * +from tests.kubernetes_mock_responses import ( + EMPTY_SERVICE, EMPTY_STATEFUL_SET, VALID_SECRET, EMPTY_DAEMON_SET, + VALID_REG_SECRET, username, password, INVALID_SECRET +) from urllib3_mock import Responses import kubernetes import json +import base64 from copy import deepcopy responses = Responses('urllib3') @@ -17,8 +21,8 @@ def setUp(self): "hostess_docker_image": "ocadotechnology/mirror-hostess", "hostess_docker_tag": 2, "image_pull_secrets": None, - "secret_name": None, - "cert_name": None, + "docker_certificate_secret": VALID_SECRET, + "ca_certificate_bundle": None, } registry_kwargs = {"metadata": {"name": "hub"}, "spec": {"upstreamUrl": "hubtest"}} @@ -34,26 +38,54 @@ def setUp(self): @responses.activate def test_update_service_neither_exist(self): '''Should create 2 empty services, then replace both of them''' - responses.add('POST', '/api/v1/namespaces/default/services', body=EMPTY_SERVICE) + responses.add( + 'POST', + '/api/v1/namespaces/default/services', + body=EMPTY_SERVICE + ) self.mirror.update_services(None, None) - self.check_calls(('POST', 'POST'), responses.calls, self.mirror.metadata) + self.check_calls( + ('POST', 'POST'), + responses.calls, + self.mirror.metadata + ) @responses.activate def test_update_service_one_exists(self): '''Should create one empty service and replace 2''' - responses.add('POST', '/api/v1/namespaces/default/services', body=EMPTY_SERVICE) - responses.add('PUT', '/api/v1/namespaces/default/services/registry-mirror-hub', '') + responses.add( + 'POST', + '/api/v1/namespaces/default/services', + body=EMPTY_SERVICE + ) + responses.add( + 'PUT', + '/api/v1/namespaces/default/services/registry-mirror-hub', + '' + ) self.mirror.update_services(kubernetes.client.V1Service( metadata=self.mirror.metadata, spec=kubernetes.client.V1ServiceSpec() ), None) - self.check_calls(('PUT', 'POST'), responses.calls, self.mirror.metadata) + self.check_calls( + ('PUT', 'POST'), + responses.calls, + self.mirror.metadata + ) @responses.activate def test_update_service_both_exist(self): '''Should replace both objects''' - responses.add('PUT', '/api/v1/namespaces/default/services/registry-mirror-hub', '') - responses.add('PUT', '/api/v1/namespaces/default/services/registry-mirror-hub', '') + responses.add( + 'PUT', + '/api/v1/namespaces/default/services/registry-mirror-hub', + '' + ) + responses.add( + 'PUT', + '/api/v1/namespaces/default/services/registry-mirror-hub', + '' + ) self.mirror.update_services(kubernetes.client.V1Service( metadata=self.mirror.metadata, spec=kubernetes.client.V1ServiceSpec() @@ -66,22 +98,35 @@ def test_update_service_both_exist(self): @responses.activate def test_update_daemon_set_exists(self): '''Should replace 1 empty daemon set''' - responses.add('PUT', '/apis/extensions/v1beta1/namespaces/default/daemonsets/registry-mirror-hub-utils', '') + responses.add( + 'PUT', + ('/apis/extensions/v1beta1/namespaces/default/daemonsets/registry' + '-mirror-hub-utils'), + '' + ) self.mirror.update_daemon_set(kubernetes.client.V1beta1DaemonSet()) self.check_calls(('PUT',), responses.calls, self.mirror.metadata) @responses.activate def test_update_daemon_set_doesnt_exist(self): '''Should create then replace a daemon set''' - responses.add('POST', '/apis/extensions/v1beta1/namespaces/default/daemonsets', body=EMPTY_DAEMON_SET) - # responses.add('PUT', '/api/v1/namespaces/default/services/registry-mirror-None', '') + responses.add( + 'POST', + '/apis/extensions/v1beta1/namespaces/default/daemonsets', + body=EMPTY_DAEMON_SET + ) self.mirror.update_daemon_set(None) self.check_calls(('POST',), responses.calls, self.mirror.metadata) @responses.activate def test_update_statefulset_exists(self): '''Should replace 1 empty stateful set''' - responses.add('PUT', '/apis/apps/v1beta1/namespaces/default/statefulsets/registry-mirror-hub', '') + responses.add( + 'PUT', + ('/apis/apps/v1beta1/namespaces/default/statefulsets/registry' + '-mirror-hub'), + '' + ) self.mirror.update_stateful_set(kubernetes.client.V1beta1StatefulSet( spec=kubernetes.client.V1beta1StatefulSetSpec( @@ -92,17 +137,38 @@ def test_update_statefulset_exists(self): @responses.activate def test_update_statefulset_doesnt_exist(self): '''Should create then replace a statefulset''' - responses.add('POST', '/apis/apps/v1beta1/namespaces/default/statefulsets', body=EMPTY_STATEFUL_SET) + responses.add( + 'POST', + '/apis/apps/v1beta1/namespaces/default/statefulsets', + body=EMPTY_STATEFUL_SET + ) self.mirror.update_stateful_set(None) self.check_calls(('POST',), responses.calls, self.mirror.metadata) @responses.activate def test_update_statefulset_credentials(self): - '''Should create the stateful set and create a secret containing the right url''' - responses.add('POST', '/apis/apps/v1beta1/namespaces/default/statefulsets', body=EMPTY_STATEFUL_SET) - responses.add('GET', '/api/v1/namespaces/default/secrets/internal-mirror', body=VALID_SECRET) - responses.add('GET', '/api/v1/namespaces/default/secrets/registry-mirror-hub', body=VALID_SECRET) - responses.add('PUT', '/api/v1/namespaces/default/secrets/registry-mirror-hub', body=VALID_REG_SECRET) + '''Should create the stateful set and create a secret containing + the right url''' + responses.add( + 'POST', + '/apis/apps/v1beta1/namespaces/default/statefulsets', + body=EMPTY_STATEFUL_SET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/internal-mirror', + body=VALID_SECRET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + body=VALID_SECRET + ) + responses.add( + 'PUT', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + body=VALID_REG_SECRET + ) self.mirror_with_credential_secret.update_stateful_set(None) statefulset_request, stateful_resp = responses.calls[3] secret_request, secret_resp = responses.calls[2] @@ -110,78 +176,192 @@ def test_update_statefulset_credentials(self): secret_json = json.loads(secret_request.body) expected_url = "https://{}:{}@{}".format(username, password, "hubtest") - self.assertEqual("registry-mirror-hub", statefulset_json['spec']['template']['spec']['containers'][0]['env'][4]['valueFrom']['secretKeyRef']['name']) - self.assertEqual(expected_url, base64.b64decode(secret_json['data']['url']).decode('utf-8')) + self.assertEqual( + "registry-mirror-hub", + statefulset_json['spec']['template'] + ['spec']['containers'][0]['env'][4] + ['valueFrom']['secretKeyRef']['name'] + ) + self.assertEqual( + expected_url, + base64.b64decode(secret_json['data']['url']).decode('utf-8') + ) @responses.activate def test_update_statefulset_create_url(self): - '''Should create the stateful set and create a secret containing the right url''' - responses.add('POST', '/apis/apps/v1beta1/namespaces/default/statefulsets', body=EMPTY_STATEFUL_SET) - responses.add('GET', '/api/v1/namespaces/default/secrets/internal-mirror', body=VALID_SECRET) - responses.add('GET', '/api/v1/namespaces/default/secrets/registry-mirror-hub', status=404) - responses.add('POST', '/api/v1/namespaces/default/secrets', body=VALID_REG_SECRET) + '''Should create the stateful set and create a secret containing + the right url''' + responses.add( + 'POST', + '/apis/apps/v1beta1/namespaces/default/statefulsets', + body=EMPTY_STATEFUL_SET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/internal-mirror', + body=VALID_SECRET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + status=404 + ) + responses.add( + 'POST', + '/api/v1/namespaces/default/secrets', + body=VALID_REG_SECRET + ) self.mirror_with_credential_secret.update_stateful_set(None) statefulset_request, stateful_resp = responses.calls[3] statefulset_json = json.loads(statefulset_request.body) - self.assertEqual(None, statefulset_json['spec']['template']['spec']['containers'][0]['env'][4].get('value')) - self.assertEqual("registry-mirror-hub", statefulset_json['spec']['template']['spec']['containers'][0]['env'][4]['valueFrom']['secretKeyRef']['name']) - + self.assertEqual( + None, + statefulset_json['spec']['template']['spec'] + ['containers'][0]['env'][4].get('value')) + self.assertEqual( + "registry-mirror-hub", + statefulset_json['spec']['template']['spec']['containers'] + [0]['env'][4]['valueFrom']['secretKeyRef']['name']) @responses.activate def test_update_statefulset_no_credentials(self): - '''Should create the stateful set and fall back to upstream url if there are no credentials''' - responses.add('POST', '/apis/apps/v1beta1/namespaces/default/statefulsets', body=EMPTY_STATEFUL_SET) - responses.add('GET', '/api/v1/namespaces/default/secrets/internal-mirror', status=404) - responses.add('GET', '/api/v1/namespaces/default/secrets/registry-mirror-hub', status=404, body='') + '''Should create the stateful set and fall back to upstream url if + there are no credentials''' + responses.add( + 'POST', + '/apis/apps/v1beta1/namespaces/default/statefulsets', + body=EMPTY_STATEFUL_SET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/internal-mirror', + status=404 + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + status=404, body='' + ) self.mirror_with_credential_secret.update_stateful_set(None) statefulset_request, stateful_resp = responses.calls[2] statefulset_json = json.loads(statefulset_request.body) self.assertEqual("https://hubtest", - statefulset_json['spec']['template']['spec']['containers'][0]['env'][4]['value']) + statefulset_json['spec']['template']['spec'] + ['containers'][0]['env'][4]['value']) @responses.activate def test_update_statefulset_invalid_secret(self): - '''Should create the stateful set and fall back to upstream url if the secret is invalid''' - responses.add('POST', '/apis/apps/v1beta1/namespaces/default/statefulsets', body=EMPTY_STATEFUL_SET) - responses.add('GET', '/api/v1/namespaces/default/secrets/internal-mirror', body=INVALID_SECRET) - responses.add('GET', '/api/v1/namespaces/default/secrets/registry-mirror-hub', status=404, body='') + '''Should create the stateful set and fall back to upstream url if + the secret is invalid''' + responses.add( + 'POST', + '/apis/apps/v1beta1/namespaces/default/statefulsets', + body=EMPTY_STATEFUL_SET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/internal-mirror', + body=INVALID_SECRET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + status=404, body='' + ) self.mirror_with_credential_secret.update_stateful_set(None) statefulset_request, stateful_resp = responses.calls[2] statefulset_json = json.loads(statefulset_request.body) self.assertEqual("https://hubtest", - statefulset_json['spec']['template']['spec']['containers'][0]['env'][4]['value']) + statefulset_json['spec']['template']['spec'] + ['containers'][0]['env'][4]['value']) @responses.activate def test_update_statefulset_valid_old_secret(self): - '''Should create the statefulset and fall back to unuathed url if secret not there''' - responses.add('POST', '/apis/apps/v1beta1/namespaces/default/statefulsets', body=EMPTY_STATEFUL_SET) - responses.add('GET', '/api/v1/namespaces/default/secrets/internal-mirror', status=404, body='') - responses.add('GET', '/api/v1/namespaces/default/secrets/registry-mirror-hub', body=VALID_REG_SECRET) - responses.add('PUT', '/api/v1/namespaces/default/secrets/registry-mirror-hub', body=VALID_REG_SECRET) + '''Should create the statefulset and fall back to unuathed url + if secret not there''' + responses.add( + 'POST', + '/apis/apps/v1beta1/namespaces/default/statefulsets', + body=EMPTY_STATEFUL_SET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/internal-mirror', + status=404, body='' + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + body=VALID_REG_SECRET + ) + responses.add( + 'PUT', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + body=VALID_REG_SECRET + ) self.mirror_with_credential_secret.update_stateful_set(None) statefulset_request, stateful_resp = responses.calls[2] statefulset_json = json.loads(statefulset_request.body) - self.assertEqual("https://hubtest", statefulset_json['spec']['template']['spec']['containers'][0]['env'][4].get('value')) + self.assertEqual( + "https://hubtest", + statefulset_json['spec']['template']['spec'] + ['containers'][0]['env'][4].get('value')) @responses.activate def test_update_statefulset_invalid_secret_valid_old_secret(self): - '''Should create the statefulset and fall back to unauthed url if secret not valid''' - responses.add('POST', '/apis/apps/v1beta1/namespaces/default/statefulsets', body=EMPTY_STATEFUL_SET) - responses.add('GET', '/api/v1/namespaces/default/secrets/internal-mirror', body=INVALID_SECRET) - responses.add('GET', '/api/v1/namespaces/default/secrets/registry-mirror-hub', body=VALID_REG_SECRET) - responses.add('PUT', '/api/v1/namespaces/default/secrets/registry-mirror-hub', body=VALID_REG_SECRET) + '''Should create the statefulset and fall back to unauthed url + if secret not valid''' + responses.add( + 'POST', + '/apis/apps/v1beta1/namespaces/default/statefulsets', + body=EMPTY_STATEFUL_SET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/internal-mirror', + body=INVALID_SECRET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + body=VALID_REG_SECRET + ) + responses.add( + 'PUT', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + body=VALID_REG_SECRET + ) self.mirror_with_credential_secret.update_stateful_set(None) statefulset_request, stateful_resp = responses.calls[2] statefulset_json = json.loads(statefulset_request.body) - self.assertEqual("https://hubtest", statefulset_json['spec']['template']['spec']['containers'][0]['env'][4].get('value')) + self.assertEqual( + "https://hubtest", + statefulset_json['spec']['template']['spec'] + ['containers'][0]['env'][4].get('value')) @responses.activate def test_update_statefulset_invalid_secret_invalid_old_secret(self): - '''Should create the statefulset and fall back to upstream url if neither secret is valid''' - responses.add('POST', '/apis/apps/v1beta1/namespaces/default/statefulsets', body=EMPTY_STATEFUL_SET) - responses.add('GET', '/api/v1/namespaces/default/secrets/internal-mirror', body=INVALID_SECRET) - responses.add('GET', '/api/v1/namespaces/default/secrets/registry-mirror-hub', body=INVALID_SECRET) + '''Should create the statefulset and fall back to upstream url if + neither secret is valid''' + responses.add( + 'POST', + '/apis/apps/v1beta1/namespaces/default/statefulsets', + body=EMPTY_STATEFUL_SET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/internal-mirror', + body=INVALID_SECRET + ) + responses.add( + 'GET', + '/api/v1/namespaces/default/secrets/registry-mirror-hub', + body=INVALID_SECRET + ) self.mirror_with_credential_secret.update_stateful_set(None) statefulset_request, stateful_resp = responses.calls[2] statefulset_json = json.loads(statefulset_request.body) - self.assertEqual('https://hubtest', statefulset_json['spec']['template']['spec']['containers'][0]['env'][4].get('value')) + self.assertEqual( + 'https://hubtest', + statefulset_json['spec']['template']['spec'] + ['containers'][0]['env'][4].get('value'))