| #!/usr/local/sbin/charm-env python3 |
| # |
| # For a usage examples, see README.md |
| # |
| # TODO |
| # |
| # - make the action idempotent (i.e. if you run it multiple times, the first |
| # run will create/delete the registry, and the reset will be a no-op and won't |
| # error out) |
| # |
| # - take only a plain authentication file, and create the encrypted version in |
| # the action |
| # |
| # - validate the parameters (make sure tlscert is a certificate, that tlskey is a |
| # proper key, etc) |
| # |
| # - when https://bugs.launchpad.net/juju/+bug/1661015 is fixed, handle the |
| # base64 encoding the parameters in the action itself |
| |
| import os |
| import sys |
| |
| from base64 import b64encode |
| |
| from charmhelpers.core.hookenv import action_get |
| from charmhelpers.core.hookenv import action_set |
| from charms.templating.jinja2 import render |
| from subprocess import call, check_output |
| |
| os.environ['PATH'] += os.pathsep + os.path.join(os.sep, 'snap', 'bin') |
| |
| deletion = action_get('delete') |
| |
| context = {} |
| |
| arch = check_output(['dpkg', '--print-architecture']).rstrip() |
| context['arch'] = arch.decode('utf-8') |
| |
| # These config options must be defined in the case of a creation |
| param_error = False |
| for param in ('tlscert', 'tlskey', 'domain', 'htpasswd', 'htpasswd-plain'): |
| value = action_get(param) |
| if not value and not deletion: |
| key = "registry-create-parameter-{}".format(param) |
| error = "failure, parameter {} is required".format(param) |
| action_set({key: error}) |
| param_error = True |
| |
| context[param] = value |
| |
| # Create the dockercfg template variable |
| dockercfg = '{"%s": {"auth": "%s", "email": "root@localhost"}}' % \ |
| (context['domain'], context['htpasswd-plain']) |
| context['dockercfg'] = b64encode(dockercfg.encode()).decode('ASCII') |
| |
| if param_error: |
| sys.exit(0) |
| |
| # This one is either true or false, no need to check if it has a "good" value. |
| context['ingress'] = action_get('ingress') |
| |
| # Declare a kubectl template when invoking kubectl |
| kubectl = ['kubectl', '--kubeconfig=/root/.kube/config'] |
| |
| # Remove deployment if requested |
| if deletion: |
| resources = ['svc/kube-registry', 'rc/kube-registry-v0', 'secrets/registry-tls-data', |
| 'secrets/registry-auth-data', 'secrets/registry-access'] |
| |
| if action_get('ingress'): |
| resources.append('ing/registry-ing') |
| |
| delete_command = kubectl + ['delete', '--ignore-not-found=true'] + resources |
| delete_response = call(delete_command) |
| if delete_response == 0: |
| action_set({'registry-delete': 'success'}) |
| else: |
| action_set({'registry-delete': 'failure'}) |
| |
| sys.exit(0) |
| |
| # Creation request |
| render('registry.yaml', '/root/cdk/addons/registry.yaml', |
| context) |
| |
| create_command = kubectl + ['create', '-f', |
| '/root/cdk/addons/registry.yaml'] |
| |
| create_response = call(create_command) |
| |
| if create_response == 0: |
| action_set({'registry-create': 'success'}) |
| |
| # Create a ConfigMap if it doesn't exist yet, else patch it. |
| # A ConfigMap is needed to change the default value for nginx' client_max_body_size. |
| # The default is 1MB, and this is the maximum size of images that can be |
| # pushed on the registry. 1MB images aren't useful, so we bump this value to 1024MB. |
| cm_name = 'nginx-load-balancer-conf' |
| check_cm_command = kubectl + ['get', 'cm', cm_name] |
| check_cm_response = call(check_cm_command) |
| |
| if check_cm_response == 0: |
| # There is an existing ConfigMap, patch it |
| patch = '{"data":{"body-size":"1024m"}}' |
| patch_cm_command = kubectl + ['patch', 'cm', cm_name, '-p', patch] |
| patch_cm_response = call(patch_cm_command) |
| |
| if patch_cm_response == 0: |
| action_set({'configmap-patch': 'success'}) |
| else: |
| action_set({'configmap-patch': 'failure'}) |
| |
| else: |
| # No existing ConfigMap, create it |
| render('registry-configmap.yaml', '/root/cdk/addons/registry-configmap.yaml', |
| context) |
| create_cm_command = kubectl + ['create', '-f', '/root/cdk/addons/registry-configmap.yaml'] |
| create_cm_response = call(create_cm_command) |
| |
| if create_cm_response == 0: |
| action_set({'configmap-create': 'success'}) |
| else: |
| action_set({'configmap-create': 'failure'}) |
| |
| # Patch the "default" serviceaccount with an imagePullSecret. |
| # This will allow the docker daemons to authenticate to our private |
| # registry automatically |
| patch = '{"imagePullSecrets":[{"name":"registry-access"}]}' |
| patch_sa_command = kubectl + ['patch', 'sa', 'default', '-p', patch] |
| patch_sa_response = call(patch_sa_command) |
| |
| if patch_sa_response == 0: |
| action_set({'serviceaccount-patch': 'success'}) |
| else: |
| action_set({'serviceaccount-patch': 'failure'}) |
| |
| |
| else: |
| action_set({'registry-create': 'failure'}) |