def cluster_auth(deployment): """ Do appropriate cluster authentication for given deployment """ config = get_config(deployment) if 'cluster' in config: cluster = config['cluster'] provider = cluster.get('provider') # Temporarily kubeconfig file temp_kubeconfig = tempfile.NamedTemporaryFile() orig_kubeconfig = os.environ.get("KUBECONFIG", None) try: os.environ["KUBECONFIG"] = temp_kubeconfig.name if provider == 'gcloud': yield from cluster_auth_gcloud(deployment, **cluster['gcloud']) elif provider == 'aws': yield from cluster_auth_aws(deployment, **cluster['aws']) elif provider == 'azure': yield from cluster_auth_azure(deployment, **cluster['azure']) else: raise ValueError( f'Unknown provider {provider} found in hubploy.yaml') finally: unset_env_var("KUBECONFIG", orig_kubeconfig)
def registry_auth(deployment, push, check_registry): """ Do appropriate registry authentication for given deployment """ if push or check_registry: config = get_config(deployment) if 'images' in config and 'registry' in config['images']: registry = config['images']['registry'] provider = registry.get('provider') if provider == 'gcloud': yield from registry_auth_gcloud( deployment, **registry['gcloud'] ) elif provider == 'aws': yield from registry_auth_aws( deployment, **registry['aws'] ) elif provider == 'azure': yield from registry_auth_azure( deployment, **registry['azure'] ) elif provider == 'dockerconfig': yield from registry_auth_dockercfg( deployment, **registry['dockerconfig'] ) else: raise ValueError( f'Unknown provider {provider} found in hubploy.yaml') else: # We actually don't need to auth, but we are yielding anyway # contextlib.contextmanager does not like it when you don't yield yield
def deploy(deployment, chart, environment, namespace=None, helm_config_overrides=None, version=None, timeout=None, force=False): """ Deploy a JupyterHub. Expects the following files to exist in current directory {chart}/ (Helm deployment chart) deployments/ - {deployment} - image/ - secrets/ - {environment}.yaml - config/ - common.yaml - {environment}.yaml A docker image from deployments/{deployment}/image is expected to be already built and available with imagebuilder. `jupyterhub.singleuser.image.tag` will be automatically set to this image tag. """ if helm_config_overrides is None: helm_config_overrides = [] config = get_config(deployment) name = f'{deployment}-{environment}' if namespace is None: namespace = name helm_config_files = [ f for f in [ os.path.join('deployments', deployment, 'config', 'common.yaml'), os.path.join('deployments', deployment, 'config', f'{environment}.yaml'), os.path.join('deployments', deployment, 'secrets', f'{environment}.yaml'), ] if os.path.exists(f) ] for image in config['images']['images']: # We can support other charts that wrap z2jh by allowing various # config paths where we set image tags and names. # We default to one sublevel, but we can do multiple levels. # With the PANGEO chart, we this could be set to `pangeo.jupyterhub.singleuser.image` helm_config_overrides.append( f'{image.helm_substitution_path}.tag={image.tag}') helm_config_overrides.append( f'{image.helm_substitution_path}.name={image.name}') helm_upgrade(name, namespace, chart, helm_config_files, helm_config_overrides, version, timeout, force)
def build_deployment(client, deployment, commit_range, push=False): config = get_config(deployment) image_path = os.path.abspath( os.path.join('deployments', deployment, 'image')) image_name = config['images']['image_name'] build_if_needed(client, image_path, image_name, commit_range, push)
def registry_auth(deployment): """ Do appropriate registry authentication for given deployment """ config = get_config(deployment) if 'images' in config and 'registry' in config['images']: registry = config['images']['registry'] provider = registry.get('provider') if provider == 'gcloud': registry_auth_gcloud(deployment, **registry['gcloud']) else: raise ValueError( f'Unknown provider {provider} found in hubploy.yaml')
def cluster_auth(deployment): """ Do appropriate cluster authentication for given deployment """ config = get_config(deployment) if 'cluster' in config: cluster = config['cluster'] provider = cluster.get('provider') if provider == 'gcloud': cluster_auth_gcloud(deployment, **cluster['gcloud']) else: raise ValueError( f'Unknown provider {provider} found in hubploy.yaml')
def cluster_auth(deployment): """ Do appropriate cluster authentication for given deployment """ config = get_config(deployment) if 'cluster' in config: cluster = config['cluster'] provider = cluster.get('provider') orig_kubeconfig = os.environ.get("KUBECONFIG", None) try: if provider == 'kubeconfig': encrypted_kubeconfig_path = os.path.join( 'deployments', deployment, 'secrets', cluster['kubeconfig']['filename'] ) with decrypt_file(encrypted_kubeconfig_path) as kubeconfig_path: os.environ["KUBECONFIG"] = kubeconfig_path yield else: # Temporarily kubeconfig file with tempfile.NamedTemporaryFile() as temp_kubeconfig: os.environ["KUBECONFIG"] = temp_kubeconfig.name if provider == 'gcloud': yield from cluster_auth_gcloud( deployment, **cluster['gcloud'] ) elif provider == 'aws': yield from cluster_auth_aws( deployment, **cluster['aws'] ) elif provider == 'azure': yield from cluster_auth_azure( deployment, **cluster['azure'] ) else: raise ValueError( f'Unknown provider {provider} found in hubploy.yaml') finally: unset_env_var("KUBECONFIG", orig_kubeconfig)
def deploy(deployment, chart, environment, namespace=None, helm_config_overrides_implicit=None, helm_config_overrides_string=None, version=None, timeout=None, force=False, atomic=False, cleanup_on_fail=False): """ Deploy a JupyterHub. Expects the following files to exist in current directory {chart}/ (Helm deployment chart) deployments/ - {deployment} - image/ (optional) - secrets/ - {environment}.yaml - config/ - common.yaml - {environment}.yaml A docker image from deployments/{deployment}/image is expected to be already built and available with imagebuilder. `jupyterhub.singleuser.image.tag` will be automatically set to this image tag. """ if helm_config_overrides_implicit is None: helm_config_overrides_implicit = [] if helm_config_overrides_string is None: helm_config_overrides_string = [] config = get_config(deployment) name = f'{deployment}-{environment}' if namespace is None: namespace = name helm_config_files = [ f for f in [ os.path.join('deployments', deployment, 'config', 'common.yaml'), os.path.join('deployments', deployment, 'config', f'{environment}.yaml'), ] if os.path.exists(f) ] helm_secret_files = [ f for f in [ # Support for secrets in same repo os.path.join('deployments', deployment, 'secrets', f'{environment}.yaml'), # Support for secrets in a submodule repo os.path.join('secrets', 'deployments', deployment, 'secrets', f'{environment}.yaml'), ] if os.path.exists(f) ] if config.get('images'): for image in config['images']['images']: # We can support other charts that wrap z2jh by allowing various # config paths where we set image tags and names. # We default to one sublevel, but we can do multiple levels. # With the PANGEO chart, we this could be set to `pangeo.jupyterhub.singleuser.image` helm_config_overrides_string.append( f'{image.helm_substitution_path}.tag={image.tag}') helm_config_overrides_string.append( f'{image.helm_substitution_path}.name={image.name}') with ExitStack() as stack: decrypted_secret_files = [ stack.enter_context(decrypt_file(f)) for f in helm_secret_files ] # Just in time for k8s access, activate the cluster credentials stack.enter_context(cluster_auth(deployment)) helm_upgrade( name, namespace, chart, helm_config_files + decrypted_secret_files, helm_config_overrides_implicit, helm_config_overrides_string, version, timeout, force, atomic, cleanup_on_fail, )