diff --git a/mirroroperator/registrymirror.py b/mirroroperator/registrymirror.py index d2edd21..9a02ba9 100644 --- a/mirroroperator/registrymirror.py +++ b/mirroroperator/registrymirror.py @@ -253,106 +253,47 @@ def generate_headless_service(self, service_headless): service_headless.spec.type = "ClusterIP" return service_headless - def generate_new_auth_url(self, credentials_secret): - """ - Method which, given a credentials secret (secret named ): - - decodes the username/password - - if they are valid, create a new authed upstream url - Args: - credentials_secret: V1Secret - - Returns: base64-encoded str or None if the url was not valid + def handle_proxy_credentials(self, env): + credentials_secret = None + if self.credentials_secret_name: + credentials_secret = self.run_action_and_parse_error(self.core_api.read_namespaced_secret, + self.credentials_secret_name, + self.namespace) + if not credentials_secret: + LOGGER.error("No secret named %s was found in the %s namespace, will use unauth access", + self.credentials_secret_name, self.namespace) + return env - """ encoded_user = credentials_secret.data.get("username") encoded_pass = credentials_secret.data.get("password") - url = None - if not (encoded_pass and encoded_user): - # log an error, keep the url at none - LOGGER.error("Secret %s does not contain username/password, defaulting to %s", - self.credentials_secret_name, self.upstreamUrl) - else: - # decode the username, update the url - username = base64.b64decode(encoded_user).decode('utf-8') - password = base64.b64decode(encoded_pass).decode('utf-8') - decoded_url = "https://{}:{}@{}".format(username, password, self.upstreamUrl) - url = base64.b64encode(decoded_url.encode('utf-8')).decode('utf-8') - - return url - - def handle_secrets(self, keypair): - credentials_secret = self.run_action_and_parse_error(self.core_api.read_namespaced_secret, - self.credentials_secret_name, - self.namespace) - reg_secret = self.run_action_and_parse_error(self.core_api.read_namespaced_secret, - self.full_name, self.namespace) - valid_secret = None - url = None - if credentials_secret: - # create a new url - url = self.generate_new_auth_url(credentials_secret) - else: - LOGGER.error("No secret named %s was found, will use unauth access", + if not (encoded_user and encoded_pass): + LOGGER.error("Secret %s does not contain username/password", self.credentials_secret_name) + return env + env.append(client.V1EnvVar(name="REGISTRY_PROXY_USERNAME", + value=None, + value_from=client.V1EnvVarSource( + secret_key_ref=client.V1SecretKeySelector( + key="username", + name=self.credentials_secret_name + ) + )) + ) + env.append(client.V1EnvVar(name="REGISTRY_PROXY_PASSWORD", + value=None, + value_from=client.V1EnvVarSource( + secret_key_ref=client.V1SecretKeySelector( + key="password", + name=self.credentials_secret_name + ) + )) + ) + LOGGER.info("Secret selected + env vars set successfully") + return env - if url: - if reg_secret: - reg_secret.metadata = self.metadata - reg_secret.data = {"url": url} - LOGGER.info("Updating the secret %s", self.full_name) - valid_secret = self.run_action_and_parse_error( - self.core_api.replace_namespaced_secret, - self.full_name, self.namespace, reg_secret - ) - else: - # create a new one - reg_secret = client.V1Secret( - metadata=self.metadata, - data={"url": url} - ) - LOGGER.info("Creating new secret %s", self.full_name) - valid_secret = self.run_action_and_parse_error(self.core_api.create_namespaced_secret, - self.namespace, reg_secret) - - if valid_secret: - keypair.value = None - keypair.value_from = client.V1EnvVarSource( - secret_key_ref=client.V1SecretKeySelector( - key="url", - name=valid_secret.metadata.name - ) - ) - LOGGER.info("Secret selected + env var set successfully") - else: - LOGGER.error("Valid authenticated url secret could not be created or found, value will default to upstream url %s", - self.upstreamUrl) - - return keypair def generate_stateful_set(self, stateful_set): - keypair = client.V1EnvVar( - name="REGISTRY_PROXY_REMOTEURL", - value="https://" + self.upstreamUrl) - if self.credentials_secret_name: - keypair = self.handle_secrets(keypair) - - env = [client.V1EnvVar(name="REGISTRY_HTTP_ADDR", - value=":5000"), - client.V1EnvVar(name="REGISTRY_HTTP_DEBUG_ADDR", - value="localhost:6000"), - client.V1EnvVar(name="REGISTRY_HTTP_TLS_CERTIFICATE", - value="/etc/registry-certs/tls.crt"), - client.V1EnvVar(name="REGISTRY_HTTP_TLS_KEY", - value="/etc/registry-certs/tls.key"), - keypair, - client.V1EnvVar(name="REGISTRY_LOG_FORMATTER", - value="logstash"), - client.V1EnvVar(name="REGISTRY_STORAGE_DELETE_ENABLED", - value="true"), - client.V1EnvVar(name="REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY", - value="/var/lib/registry") - ] stateful_set.metadata = self.metadata stateful_set.spec.replicas = 2 pod_labels = {'component': 'registry'} @@ -395,6 +336,26 @@ def generate_stateful_set(self, stateful_set): read_only=True ) ) + + env = [client.V1EnvVar(name="REGISTRY_PROXY_REMOTEURL", + value="https://" + self.upstreamUrl), + client.V1EnvVar(name="REGISTRY_HTTP_ADDR", + value=":5000"), + client.V1EnvVar(name="REGISTRY_HTTP_DEBUG_ADDR", + value="localhost:6000"), + client.V1EnvVar(name="REGISTRY_HTTP_TLS_CERTIFICATE", + value="/etc/registry-certs/tls.crt"), + client.V1EnvVar(name="REGISTRY_HTTP_TLS_KEY", + value="/etc/registry-certs/tls.key"), + client.V1EnvVar(name="REGISTRY_LOG_FORMATTER", + value="logstash"), + client.V1EnvVar(name="REGISTRY_STORAGE_DELETE_ENABLED", + value="true"), + client.V1EnvVar(name="REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY", + value="/var/lib/registry") + ] + env = self.handle_proxy_credentials(env) + stateful_set.spec.template = client.V1PodTemplateSpec( metadata=client.V1ObjectMeta( labels=pod_labels diff --git a/tests/kubernetes_mock_responses.py b/tests/kubernetes_mock_responses.py index 9595619..20a81a8 100644 --- a/tests/kubernetes_mock_responses.py +++ b/tests/kubernetes_mock_responses.py @@ -202,25 +202,7 @@ }, "type": "Opaque" } -url = "https://{}:{}@{}".format(username, password, "hubtest") -url = base64.b64encode(url.encode('utf-8')).decode('utf-8') -valid_reg_secret = { - "apiVersion": "v1", - "data": { - "url": url - }, - "kind": "Secret", - "metadata": { - "creationTimestamp": "2017-09-13T10:20:26Z", - "name": "registry-mirror-hub", - "namespace": "default", - "resourceVersion": "7889", - "selfLink": "/api/v1/namespaces/default/secrets/internal-mirror", - "uid": "294e16e7-986d-11e7-9c1f-0800275e72fe" - }, - "type": "Opaque" -} -VALID_REG_SECRET = json.dumps(valid_reg_secret) + VALID_SECRET = json.dumps(valid_secret) INVALID_SECRET = """ diff --git a/tests/test_operator.py b/tests/test_operator.py index f876c39..380613b 100644 --- a/tests/test_operator.py +++ b/tests/test_operator.py @@ -73,7 +73,7 @@ def test_will_read_crds_blanks_already_exist(self): @responses.activate def test_will_read_crds_blanks_dont_exist(self): - '''Should listen to CRDs being streamed + call apis appropriately. In this case the objects don't alreadu exist''' + '''Should listen to CRDs being streamed + call apis appropriately. In this case the objects don't already exist''' stream_generator = stream_mock() responses.add('GET', '/api/v1/namespaces/default/services/registry-mirror-hub', status=404, body='{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"services \\"registry-mirror-internal\\" not found","reason":"NotFound","details":{"name":"registry-mirror-internal","kind":"services"},"code":404}') responses.add('GET', '/api/v1/namespaces/default/services/registry-mirror-hub-headless', status=404) diff --git a/tests/test_regmirror.py b/tests/test_regmirror.py index fce3503..8e81768 100644 --- a/tests/test_regmirror.py +++ b/tests/test_regmirror.py @@ -2,7 +2,7 @@ from tests.kubernetes_test_case import KubernetesTestCase from tests.kubernetes_mock_responses import ( EMPTY_SERVICE, EMPTY_STATEFUL_SET, VALID_SECRET, EMPTY_DAEMON_SET, - VALID_REG_SECRET, username, password, INVALID_SECRET + username, password, INVALID_SECRET ) from urllib3_mock import Responses import kubernetes @@ -144,224 +144,3 @@ def test_update_statefulset_doesnt_exist(self): ) 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 - ) - self.mirror_with_credential_secret.update_stateful_set(None) - statefulset_request, stateful_resp = responses.calls[3] - secret_request, secret_resp = responses.calls[2] - statefulset_json = json.loads(statefulset_request.body) - 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') - ) - - @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 - ) - 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']) - - @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='' - ) - 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']) - - @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='' - ) - 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']) - - @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 - ) - 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')) - - @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 - ) - 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')) - - @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 - ) - 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'))