#!/usr/bin/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 os.environ['PATH'] += os.pathsep + os.path.join(os.sep, 'snap', 'bin') deletion = action_get('delete') context = {} # 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/cdk/kubeconfig'] # 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'})