From 34f8ec6a29af7a499ce6ab1aab4a484380637889 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Sat, 20 Jan 2024 10:41:21 +0100 Subject: [PATCH 01/37] CH-110 jupyterhub update wip --- .../deploy/resources/hub/jupyterhub_config.py | 148 +- .../jupyterhub/deploy/resources/hub/z2jh.py | 21 +- .../jupyterhub/deploy/templates/NOTES.txt | 158 + .../deploy/templates/_helpers-auth-rework.tpl | 18 +- .../deploy/templates/_helpers-names.tpl | 62 +- .../deploy/templates/_helpers-netpol.tpl | 101 + .../jupyterhub/deploy/templates/_helpers.tpl | 63 +- .../deploy/templates/hub/configmap.yaml | 1 + .../deploy/templates/hub/deployment.yaml | 24 +- .../deploy/templates/hub/netpol.yaml | 25 +- .../jupyterhub/deploy/templates/hub/pdb.yaml | 4 - .../jupyterhub/deploy/templates/hub/rbac.yaml | 15 +- .../deploy/templates/hub/serviceaccount.yaml | 12 + .../deploy/templates/image-pull-secret.yaml | 15 + .../image-puller/_helpers-daemonset.tpl | 51 +- .../deploy/templates/image-puller/job.yaml | 13 +- .../templates/image-puller/priorityclass.yaml | 18 + .../deploy/templates/image-puller/rbac.yaml | 27 +- .../image-puller/serviceaccount.yaml | 21 + .../templates/proxy/autohttps/_README.txt | 9 - .../templates/proxy/autohttps/configmap.yaml | 28 - .../templates/proxy/autohttps/deployment.yaml | 141 - .../templates/proxy/autohttps/rbac.yaml | 40 - .../templates/proxy/autohttps/service.yaml | 25 - .../deploy/templates/proxy/deployment.yaml | 14 +- .../deploy/templates/proxy/netpol.yaml | 24 +- .../deploy/templates/proxy/pdb.yaml | 4 - .../deploy/templates/proxy/service.yaml | 9 +- .../templates/scheduling/priorityclass.yaml | 13 - .../scheduling/user-placeholder/pdb.yaml | 4 - .../user-placeholder/priorityclass.yaml | 13 - .../user-placeholder/statefulset.yaml | 15 +- .../scheduling/user-scheduler/configmap.yaml | 20 +- .../scheduling/user-scheduler/deployment.yaml | 31 +- .../scheduling/user-scheduler/pdb.yaml | 4 - .../scheduling/user-scheduler/rbac.yaml | 78 +- .../user-scheduler/serviceaccount.yaml | 14 + .../deploy/templates/singleuser/netpol.yaml | 39 +- .../deploy/templates/singleuser/secret.yaml | 17 + .../jupyterhub/deploy/values.schema.yaml | 3014 +++++++++++++++++ applications/jupyterhub/deploy/values.yaml | 276 +- .../jupyterhub/zero-to-jupyterhub-k8s | 1 + 42 files changed, 4013 insertions(+), 617 deletions(-) create mode 100644 applications/jupyterhub/deploy/templates/NOTES.txt create mode 100644 applications/jupyterhub/deploy/templates/_helpers-netpol.tpl create mode 100644 applications/jupyterhub/deploy/templates/hub/serviceaccount.yaml create mode 100644 applications/jupyterhub/deploy/templates/image-pull-secret.yaml create mode 100644 applications/jupyterhub/deploy/templates/image-puller/priorityclass.yaml create mode 100644 applications/jupyterhub/deploy/templates/image-puller/serviceaccount.yaml delete mode 100755 applications/jupyterhub/deploy/templates/proxy/autohttps/_README.txt delete mode 100755 applications/jupyterhub/deploy/templates/proxy/autohttps/configmap.yaml delete mode 100755 applications/jupyterhub/deploy/templates/proxy/autohttps/deployment.yaml delete mode 100755 applications/jupyterhub/deploy/templates/proxy/autohttps/rbac.yaml delete mode 100755 applications/jupyterhub/deploy/templates/proxy/autohttps/service.yaml create mode 100644 applications/jupyterhub/deploy/templates/scheduling/user-scheduler/serviceaccount.yaml create mode 100644 applications/jupyterhub/deploy/templates/singleuser/secret.yaml create mode 100644 applications/jupyterhub/deploy/values.schema.yaml create mode 160000 applications/jupyterhub/zero-to-jupyterhub-k8s diff --git a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py index d4b3cee2b..8ec801ee5 100755 --- a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py +++ b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py @@ -1,9 +1,17 @@ +# load the config object (satisfies linters) +c = get_config() # noqa + +import glob import os import re import sys -import logging +from jupyterhub.utils import url_path_join +from kubernetes_asyncio import client from tornado.httpclient import AsyncHTTPClient + +#CLOUDHARNESS: EDIT START +import logging from kubernetes import client from jupyterhub.utils import url_path_join @@ -12,7 +20,7 @@ harness_hub() # activates harness hooks on jupyterhub except Exception as e: logging.error("could not import harness_jupyter", exc_info=True) - +# CLOUDHARNESS: EDIT END # Make sure that modules placed in the same directory as the jupyterhub config are added to the pythonpath configuration_directory = os.path.dirname(os.path.realpath(__file__)) @@ -20,39 +28,13 @@ from z2jh import ( get_config, - set_config_if_not_none, get_name, get_name_env, get_secret_value, + set_config_if_not_none, ) -print('Base url is', c.JupyterHub.get('base_url', '/')) - -# Configure JupyterHub to use the curl backend for making HTTP requests, -# rather than the pure-python implementations. The default one starts -# being too slow to make a large number of requests to the proxy API -# at the rate required. -AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient") - -c.JupyterHub.spawner_class = 'kubespawner.KubeSpawner' - -# Connect to a proxy running in a different pod -c.ConfigurableHTTPProxy.api_url = 'http://{}:{}'.format(os.environ['PROXY_API_SERVICE_HOST'], int(os.environ['PROXY_API_SERVICE_PORT'])) -c.ConfigurableHTTPProxy.should_start = False - -# Do not shut down user pods when hub is restarted -c.JupyterHub.cleanup_servers = False - -# Check that the proxy has routes appropriately setup -c.JupyterHub.last_activity_interval = 60 - -# Don't wait at all before redirecting a spawning user to the progress page -c.JupyterHub.tornado_settings = { - 'slow_spawn_timeout': 0, -} - - def camelCaseify(s): """convert snake_case to camelCase @@ -173,6 +155,7 @@ def camelCaseify(s): ("events_enabled", "events"), ("extra_labels", None), ("extra_annotations", None), + # ("allow_privilege_escalation", None), # Managed manually below ("uid", None), ("fs_gid", None), ("service_account", "serviceAccountName"), @@ -206,10 +189,19 @@ def camelCaseify(s): if image: tag = get_config("singleuser.image.tag") if tag: - image = "{}:{}".format(image, tag) + image = f"{image}:{tag}" c.KubeSpawner.image = image +# allow_privilege_escalation defaults to False in KubeSpawner 2+. Since its a +# property where None, False, and True all are valid values that users of the +# Helm chart may want to set, we can't use the set_config_if_not_none helper +# function as someone may want to override the default False value to None. +# +c.KubeSpawner.allow_privilege_escalation = get_config( + "singleuser.allowPrivilegeEscalation" +) + # Combine imagePullSecret.create (single), imagePullSecrets (list), and # singleuser.image.pullSecrets (list). image_pull_secrets = [] @@ -255,7 +247,7 @@ def camelCaseify(s): pass else: raise ValueError( - "Unrecognized value for matchNodePurpose: %r" % match_node_purpose + f"Unrecognized value for matchNodePurpose: {match_node_purpose}" ) # Combine the common tolerations for user pods with singleuser tolerations @@ -271,7 +263,7 @@ def camelCaseify(s): pvc_name_template = get_config("singleuser.storage.dynamic.pvcNameTemplate") c.KubeSpawner.pvc_name_template = pvc_name_template volume_name_template = get_config("singleuser.storage.dynamic.volumeNameTemplate") - c.KubeSpawner.storage_pvc_ensure = False + c.KubeSpawner.storage_pvc_ensure = True set_config_if_not_none( c.KubeSpawner, "storage_class", "singleuser.storage.dynamic.storageClass" ) @@ -354,41 +346,62 @@ def camelCaseify(s): ) c.JupyterHub.services = [] +c.JupyterHub.load_roles = [] +# jupyterhub-idle-culler's permissions are scoped to what it needs only, see +# https://github.com/jupyterhub/jupyterhub-idle-culler#permissions. +# if get_config("cull.enabled", False): + jupyterhub_idle_culler_role = { + "name": "jupyterhub-idle-culler", + "scopes": [ + "list:users", + "read:users:activity", + "read:servers", + "delete:servers", + # "admin:users", # dynamically added if --cull-users is passed + ], + # assign the role to a jupyterhub service, so it gains these permissions + "services": ["jupyterhub-idle-culler"], + } + cull_cmd = ["python3", "-m", "jupyterhub_idle_culler"] base_url = c.JupyterHub.get("base_url", "/") cull_cmd.append("--url=http://localhost:8081" + url_path_join(base_url, "hub/api")) cull_timeout = get_config("cull.timeout") if cull_timeout: - cull_cmd.append("--timeout=%s" % cull_timeout) + cull_cmd.append(f"--timeout={cull_timeout}") cull_every = get_config("cull.every") if cull_every: - cull_cmd.append("--cull-every=%s" % cull_every) + cull_cmd.append(f"--cull-every={cull_every}") cull_concurrency = get_config("cull.concurrency") if cull_concurrency: - cull_cmd.append("--concurrency=%s" % cull_concurrency) + cull_cmd.append(f"--concurrency={cull_concurrency}") if get_config("cull.users"): cull_cmd.append("--cull-users") + jupyterhub_idle_culler_role["scopes"].append("admin:users") + + if not get_config("cull.adminUsers"): + cull_cmd.append("--cull-admin-users=false") if get_config("cull.removeNamedServers"): cull_cmd.append("--remove-named-servers") cull_max_age = get_config("cull.maxAge") if cull_max_age: - cull_cmd.append("--max-age=%s" % cull_max_age) + cull_cmd.append(f"--max-age={cull_max_age}") c.JupyterHub.services.append( { - "name": "cull-idle", - "admin": True, + "name": "jupyterhub-idle-culler", "command": cull_cmd, } ) + c.JupyterHub.load_roles.append(jupyterhub_idle_culler_role) for key, service in get_config("hub.services", {}).items(): # c.JupyterHub.services is a list of dicts, but @@ -402,26 +415,44 @@ def camelCaseify(s): c.JupyterHub.services.append(service) +for key, role in get_config("hub.loadRoles", {}).items(): + # c.JupyterHub.load_roles is a list of dicts, but + # hub.loadRoles is a dict of dicts to make the config mergable + role.setdefault("name", key) + + c.JupyterHub.load_roles.append(role) + +# respect explicit null command (distinct from unspecified) +# this avoids relying on KubeSpawner.cmd's default being None +_unspecified = object() +specified_cmd = get_config("singleuser.cmd", _unspecified) +if specified_cmd is not _unspecified: + c.Spawner.cmd = specified_cmd -set_config_if_not_none(c.Spawner, "cmd", "singleuser.cmd") set_config_if_not_none(c.Spawner, "default_url", "singleuser.defaultUrl") -cloud_metadata = get_config("singleuser.cloudMetadata", {}) +cloud_metadata = get_config("singleuser.cloudMetadata") if cloud_metadata.get("blockWithIptables") == True: # Use iptables to block access to cloud metadata by default network_tools_image_name = get_config("singleuser.networkTools.image.name") network_tools_image_tag = get_config("singleuser.networkTools.image.tag") + network_tools_resources = get_config("singleuser.networkTools.resources") + ip = cloud_metadata["ip"] ip_block_container = client.V1Container( name="block-cloud-metadata", image=f"{network_tools_image_name}:{network_tools_image_tag}", command=[ "iptables", - "-A", + "--append", "OUTPUT", - "-d", - cloud_metadata.get("ip", "169.254.169.254"), - "-j", + "--protocol", + "tcp", + "--destination", + ip, + "--destination-port", + "80", + "--jump", "DROP", ], security_context=client.V1SecurityContext( @@ -429,6 +460,7 @@ def camelCaseify(s): run_as_user=0, capabilities=client.V1Capabilities(add=["NET_ADMIN"]), ), + resources=network_tools_resources, ) c.KubeSpawner.init_containers.append(ip_block_container) @@ -438,17 +470,6 @@ def camelCaseify(s): c.JupyterHub.log_level = "DEBUG" c.Spawner.debug = True -# load /usr/local/etc/jupyterhub/jupyterhub_config.d config files -config_dir = "/usr/local/etc/jupyterhub/jupyterhub_config.d" -if os.path.isdir(config_dir): - for file_path in sorted(glob.glob(f"{config_dir}/*.py")): - file_name = os.path.basename(file_path) - print(f"Loading {config_dir} config: {file_name}") - with open(file_path) as f: - file_content = f.read() - # compiling makes debugging easier: https://stackoverflow.com/a/437857 - exec(compile(source=file_content, filename=file_name, mode="exec")) - # load potentially seeded secrets # # NOTE: ConfigurableHTTPProxy.auth_token is set through an environment variable @@ -471,11 +492,23 @@ def camelCaseify(s): cfg.pop("keys", None) c[app].update(cfg) +# load /usr/local/etc/jupyterhub/jupyterhub_config.d config files +config_dir = "/usr/local/etc/jupyterhub/jupyterhub_config.d" +if os.path.isdir(config_dir): + for file_path in sorted(glob.glob(f"{config_dir}/*.py")): + file_name = os.path.basename(file_path) + print(f"Loading {config_dir} config: {file_name}") + with open(file_path) as f: + file_content = f.read() + # compiling makes debugging easier: https://stackoverflow.com/a/437857 + exec(compile(source=file_content, filename=file_name, mode="exec")) + # execute hub.extraConfig entries for key, config_py in sorted(get_config("hub.extraConfig", {}).items()): - print("Loading extra config: %s" % key) + print(f"Loading extra config: {key}") exec(config_py) +# CLOUDHARNESS: EDIT START # Allow switching authenticators easily auth_type = get_config('hub.config.JupyterHub.authenticator_class') email_domain = 'local' @@ -525,4 +558,5 @@ def camelCaseify(s): c.apps = get_config('apps') c.registry = get_config('registry') c.domain = get_config('root.domain') -c.namespace = get_config('root.namespace') \ No newline at end of file +c.namespace = get_config('root.namespace') +# CLOUDHARNESS: EDIT END \ No newline at end of file diff --git a/applications/jupyterhub/deploy/resources/hub/z2jh.py b/applications/jupyterhub/deploy/resources/hub/z2jh.py index 834a6b6c8..fc368f64e 100755 --- a/applications/jupyterhub/deploy/resources/hub/z2jh.py +++ b/applications/jupyterhub/deploy/resources/hub/z2jh.py @@ -3,15 +3,15 @@ Methods here can be imported by extraConfig in values.yaml """ -from collections import Mapping -from functools import lru_cache import os -import re +from collections.abc import Mapping +from functools import lru_cache import yaml + # memoize so we only load config once -@lru_cache() +@lru_cache def _load_config(): """Load the Helm chart configuration used to render the Helm templates of the chart from a mounted k8s Secret, and merge in values from an optionally @@ -27,6 +27,7 @@ def _load_config(): cfg = _merge_dictionaries(cfg, values) else: print(f"No config at {path}") + # EDIT: CLOUDHARNESS START path = f"/opt/cloudharness/resources/allvalues.yaml" if os.path.exists(path): print("Loading global CloudHarness config at", path) @@ -34,11 +35,11 @@ def _load_config(): values = yaml.safe_load(f) cfg = _merge_dictionaries(cfg, values) cfg['root'] = values - + # EDIT: CLOUDHARNESS END return cfg -@lru_cache() +@lru_cache def _get_config_value(key): """Load value from the k8s ConfigMap given a key.""" @@ -50,7 +51,7 @@ def _get_config_value(key): raise Exception(f"{path} not found!") -@lru_cache() +@lru_cache def get_secret_value(key, default="never-explicitly-set"): """Load value from the user managed k8s Secret or the default k8s Secret given a key.""" @@ -117,7 +118,7 @@ def get_config(key, default=None): else: value = value[level] - + # EDIT: CLOUDHARNESS START if value and isinstance(value, str): replace_var = re.search("{{.*?}}", value) if replace_var: @@ -128,6 +129,7 @@ def get_config(key, default=None): if repl: print("replace", variable, "in", value, ":", repl) value = re.sub("{{.*?}}", repl, value) + # EDIT: CLOUDHARNESS END return value @@ -137,6 +139,5 @@ def set_config_if_not_none(cparent, name, key): configuration item if not None """ data = get_config(key) - if data is not None: - setattr(cparent, name, data) \ No newline at end of file + setattr(cparent, name, data) diff --git a/applications/jupyterhub/deploy/templates/NOTES.txt b/applications/jupyterhub/deploy/templates/NOTES.txt new file mode 100644 index 000000000..9769a9c72 --- /dev/null +++ b/applications/jupyterhub/deploy/templates/NOTES.txt @@ -0,0 +1,158 @@ +{{- $proxy_service := include "jupyterhub.proxy-public.fullname" . -}} + +{{- /* Generated with https://patorjk.com/software/taag/#p=display&h=0&f=Slant&t=JupyterHub */}} +. __ __ __ __ __ + / / __ __ ____ __ __ / /_ ___ _____ / / / / __ __ / /_ + __ / / / / / / / __ \ / / / / / __/ / _ \ / ___/ / /_/ / / / / / / __ \ +/ /_/ / / /_/ / / /_/ / / /_/ / / /_ / __/ / / / __ / / /_/ / / /_/ / +\____/ \__,_/ / .___/ \__, / \__/ \___/ /_/ /_/ /_/ \__,_/ /_.___/ + /_/ /____/ + + You have successfully installed the official JupyterHub Helm chart! + +### Installation info + + - Kubernetes namespace: {{ .Release.Namespace }} + - Helm release name: {{ .Release.Name }} + - Helm chart version: {{ .Chart.Version }} + - JupyterHub version: {{ .Chart.AppVersion }} + - Hub pod packages: See https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/{{ include "jupyterhub.chart-version-to-git-ref" .Chart.Version }}/images/hub/requirements.txt + +### Followup links + + - Documentation: https://z2jh.jupyter.org + - Help forum: https://discourse.jupyter.org + - Social chat: https://gitter.im/jupyterhub/jupyterhub + - Issue tracking: https://github.com/jupyterhub/zero-to-jupyterhub-k8s/issues + +### Post-installation checklist + + - Verify that created Pods enter a Running state: + + kubectl --namespace={{ .Release.Namespace }} get pod + + If a pod is stuck with a Pending or ContainerCreating status, diagnose with: + + kubectl --namespace={{ .Release.Namespace }} describe pod + + If a pod keeps restarting, diagnose with: + + kubectl --namespace={{ .Release.Namespace }} logs --previous + {{- println }} + + {{- if eq .Values.apps.jupyterhub.proxy.service.type "LoadBalancer" }} + - Verify an external IP is provided for the k8s Service {{ $proxy_service }}. + + kubectl --namespace={{ .Release.Namespace }} get service {{ $proxy_service }} + + If the external ip remains , diagnose with: + + kubectl --namespace={{ .Release.Namespace }} describe service {{ $proxy_service }} + {{- end }} + + - Verify web based access: + {{- println }} + {{- if .Values.apps.jupyterhub.ingress.enabled }} + {{- range $host := .Values.apps.jupyterhub.ingress.hosts }} + Try insecure HTTP access: http://{{ $host }}{{ $.Values.apps.jupyterhub.hub.baseUrl | trimSuffix "/" }}/ + {{- end }} + + {{- range $tls := .Values.apps.jupyterhub.ingress.tls }} + {{- range $host := $tls.hosts }} + Try secure HTTPS access: https://{{ $host }}{{ $.Values.apps.jupyterhub.hub.baseUrl | trimSuffix "/" }}/ + {{- end }} + {{- end }} + {{- else }} + You have not configured a k8s Ingress resource so you need to access the k8s + Service {{ $proxy_service }} directly. + {{- println }} + + {{- if eq .Values.apps.jupyterhub.proxy.service.type "NodePort" }} + The k8s Service {{ $proxy_service }} is exposed via NodePorts. That means + that all the k8s cluster's nodes are exposing the k8s Service via those + ports. + + Try insecure HTTP access: http://:{{ .Values.apps.jupyterhub.proxy.service.nodePorts.http | default "no-http-nodeport-set"}} + Try secure HTTPS access: https://:{{ .Values.apps.jupyterhub.proxy.service.nodePorts.https | default "no-https-nodeport-set" }} + + {{- else }} + If your computer is outside the k8s cluster, you can port-forward traffic to + the k8s Service {{ $proxy_service }} with kubectl to access it from your + computer. + + kubectl --namespace={{ .Release.Namespace }} port-forward service/{{ $proxy_service }} 8080:http + + Try insecure HTTP access: http://localhost:8080 + {{- end }} + {{- end }} + {{- println }} + + + + + +{{- /* + Warnings for likely misconfigurations +*/}} + +{{- if and (not .Values.apps.jupyterhub.scheduling.podPriority.enabled) (and .Values.apps.jupyterhub.scheduling.userPlaceholder.enabled .Values.apps.jupyterhub.scheduling.userPlaceholder.replicas) }} +################################################################################# +###### WARNING: You are using user placeholders without pod priority ##### +###### enabled*, either enable pod priority or stop using the ##### +###### user placeholders** to avoid having placeholders that ##### +###### refuse to make room for a real user. ##### +###### ##### +###### *scheduling.podPriority.enabled ##### +###### **scheduling.userPlaceholder.enabled ##### +###### **scheduling.userPlaceholder.replicas ##### +################################################################################# +{{- println }} +{{- end }} + + + + + +{{- /* + Breaking changes and failures for likely misconfigurations. +*/}} + +{{- $breaking := "" }} +{{- $breaking_title := "\n" }} +{{- $breaking_title = print $breaking_title "\n#################################################################################" }} +{{- $breaking_title = print $breaking_title "\n###### BREAKING: The config values passed contained no longer accepted #####" }} +{{- $breaking_title = print $breaking_title "\n###### options. See the messages below for more details. #####" }} +{{- $breaking_title = print $breaking_title "\n###### #####" }} +{{- $breaking_title = print $breaking_title "\n###### To verify your updated config is accepted, you can use #####" }} +{{- $breaking_title = print $breaking_title "\n###### the `helm template` command. #####" }} +{{- $breaking_title = print $breaking_title "\n#################################################################################" }} + + +{{- /* + This is an example (in a helm template comment) on how to detect and + communicate with regards to a breaking chart config change. + + {{- if hasKey .Values.apps.jupyterhub.singleuser.cloudMetadata "enabled" }} + {{- $breaking = print $breaking "\n\nCHANGED: singleuser.cloudMetadata.enabled must as of 1.0.0 be configured using singleuser.cloudMetadata.blockWithIptables with the opposite value." }} + {{- end }} +*/}} + + +{{- if hasKey .Values.apps.jupyterhub.rbac "enabled" }} +{{- $breaking = print $breaking "\n\nCHANGED: rbac.enabled must as of version 2.0.0 be configured via rbac.create and .serviceAccount.create." }} +{{- end }} + + +{{- if hasKey .Values.apps.jupyterhub.hub "fsGid" }} +{{- $breaking = print $breaking "\n\nCHANGED: hub.fsGid must as of version 2.0.0 be configured via hub.podSecurityContext.fsGroup." }} +{{- end }} + + +{{- if and .Values.apps.jupyterhub.singleuser.cloudMetadata.blockWithIptables (and .Values.apps.jupyterhub.singleuser.networkPolicy.enabled .Values.apps.jupyterhub.singleuser.networkPolicy.egressAllowRules.cloudMetadataServer) }} +{{- $breaking = print $breaking "\n\nCHANGED: singleuser.cloudMetadata.blockWithIptables must as of version 3.0.0 not be configured together with singleuser.networkPolicy.egressAllowRules.cloudMetadataServer as it leads to an ambiguous configuration." }} +{{- end }} + + +{{- if $breaking }} +{{- fail (print $breaking_title $breaking "\n\n") }} +{{- end }} diff --git a/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl b/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl index b742a1266..3159d1033 100644 --- a/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl +++ b/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl @@ -168,30 +168,30 @@ ldap.dn.user.useLookupName: LDAPAuthenticator.use_lookup_dn_username {{- $c := dict }} {{- $result := (dict "hub" (dict "config" $c)) }} {{- /* - Flattens the config in .Values.apps.jupyterhub.auth to a format of + Flattens the config in .Values.apps.jupyterhub.apps.jupyterhub.auth to a format of "keyX.keyY...": "value". Writes output to $c. */}} - {{- include "jupyterhub.flattenDict" (list $c (omit .Values.apps.jupyterhub.auth "type" "custom")) }} + {{- include "jupyterhub.flattenDict" (list $c (omit .Values.apps.jupyterhub.apps.jupyterhub.auth "type" "custom")) }} {{- /* Transform the flattened config using a dictionary representing the old z2jh config, output the result in $c. */}} - {{- include "jupyterhub.authDep.remapOldToNew.mappable" (list $c .Values.apps.jupyterhub.global.safeToShowValues) }} + {{- include "jupyterhub.authDep.remapOldToNew.mappable" (list $c .Values.apps.jupyterhub.apps.jupyterhub.global.safeToSho.Values.apps.jupyterhub. }} - {{- $class_old_config_key := .Values.apps.jupyterhub.auth.type | default "" }} {{- /* ldap - github */}} + {{- $class_old_config_key := .Values.apps.jupyterhub.apps.jupyterhub.auth.type | default "" }} {{- /* ldap - github */}} {{- $class_new_entrypoint := "" }} {{- /* ldapauthenticator.LDAPAuthenticator - github */}} {{- $class_new_config_key := "" }} {{- /* LDAPAuthenticator - GitHubOAuthenticator */}} {{- /* SET $class_new_entrypoint, $class_new_config_key */}} {{- if eq $class_old_config_key "custom" }} - {{- $class_new_entrypoint = .Values.apps.jupyterhub.auth.custom.className | default "custom.className wasn't configured!" }} + {{- $class_new_entrypoint = .Values.apps.jupyterhub.apps.jupyterhub.auth.custom.className | default "custom.className wasn't configured!" }} {{- $class_new_config_key = $class_new_entrypoint | splitList "." | last }} {{- /* UPDATE c dict explicitly with auth.custom.config */}} - {{- if .Values.apps.jupyterhub.auth.custom.config }} - {{- $custom_config := merge (dict) .Values.apps.jupyterhub.auth.custom.config }} - {{- if not .Values.apps.jupyterhub.global.safeToShowValues }} + {{- if .Values.apps.jupyterhub.apps.jupyterhub.auth.custom.config }} + {{- $custom_config := merge (dict) .Values.apps.jupyterhub.apps.jupyterhub.auth.custom.config }} + {{- if not .Values.apps.jupyterhub.apps.jupyterhub.global.safeToSho.Values.apps.jupyterhub.}} {{- range $key, $val := $custom_config }} {{- $_ := set $custom_config $key "***" }} {{- end }} @@ -213,7 +213,7 @@ The JupyterHub Helm chart's auth config has been reworked and requires changes. The new way to configure authentication in chart version 0.11.0+ is printed below for your convenience. The values are not shown by default to ensure no -secrets are exposed, run helm upgrade with --set global.safeToShowValues=true +secrets are exposed, run helm upgrade with --set global.safeToSho.Values.apps.jupyterhub.true to show them. {{ $result | toYaml }} diff --git a/applications/jupyterhub/deploy/templates/_helpers-names.tpl b/applications/jupyterhub/deploy/templates/_helpers-names.tpl index e9cf7bb64..401d601a6 100644 --- a/applications/jupyterhub/deploy/templates/_helpers-names.tpl +++ b/applications/jupyterhub/deploy/templates/_helpers-names.tpl @@ -3,8 +3,8 @@ parent charts to reference these dynamic resource names. To avoid duplicating documentation, for more information, please see the the - fullnameOverride entry in schema.yaml or the configuration reference that - schema.yaml renders to. + fullnameOverride entry in values.schema.yaml or the configuration reference + that values.schema.yaml renders to. https://z2jh.jupyter.org/en/latest/resources/reference.html#fullnameOverride */}} @@ -38,8 +38,8 @@ {{- $name_override := .Values.apps.jupyterhub.nameOverride }} {{- if ne .Chart.Name "jupyterhub" }} {{- if .Values.apps.jupyterhub.jupyterhub }} - {{- $fullname_override = .Values.apps.jupyterhub.fullnameOverride }} - {{- $name_override = .Values.apps.jupyterhub.nameOverride }} + {{- $fullname_override = .Values.apps.jupyterhub.jupyterhub.fullnameOverride }} + {{- $name_override = .Values.apps.jupyterhub.jupyterhub.nameOverride }} {{- end }} {{- end }} @@ -76,12 +76,23 @@ {{- include "jupyterhub.fullname.dash" . }}hub {{- end }} +{{- /* hub-serviceaccount ServiceAccount */}} +{{- define "jupyterhub.hub-serviceaccount.fullname" -}} + {{- if .Values.apps.jupyterhub.hub.serviceAccount.create }} + {{- .Values.apps.jupyterhub.hub.serviceAccount.name | default (include "jupyterhub.hub.fullname" .) }} + {{- else }} + {{- .Values.apps.jupyterhub.hub.serviceAccount.name | default "default" }} + {{- end }} +{{- end }} + {{- /* hub-existing-secret Secret */}} {{- define "jupyterhub.hub-existing-secret.fullname" -}} {{- /* A hack to avoid issues from invoking this from a parent Helm chart. */}} {{- $existing_secret := .Values.apps.jupyterhub.hub.existingSecret }} {{- if ne .Chart.Name "jupyterhub" }} - {{- $existing_secret = .Values.apps.jupyterhub.hub.existingSecret }} + {{- if .Values.apps.jupyterhub.jupyterhub }} + {{- $existing_secret = .Values.apps.jupyterhub.jupyterhub.hub.existingSecret }} + {{- end }} {{- end }} {{- if $existing_secret }} {{- $existing_secret }} @@ -133,11 +144,29 @@ {{- include "jupyterhub.fullname.dash" . }}autohttps {{- end }} +{{- /* autohttps-serviceaccount ServiceAccount */}} +{{- define "jupyterhub.autohttps-serviceaccount.fullname" -}} + {{- if .Values.apps.jupyterhub.proxy.traefik.serviceAccount.create }} + {{- .Values.apps.jupyterhub.proxy.traefik.serviceAccount.name | default (include "jupyterhub.autohttps.fullname" .) }} + {{- else }} + {{- .Values.apps.jupyterhub.proxy.traefik.serviceAccount.name | default "default" }} + {{- end }} +{{- end }} + {{- /* user-scheduler Deployment */}} {{- define "jupyterhub.user-scheduler-deploy.fullname" -}} {{- include "jupyterhub.fullname.dash" . }}user-scheduler {{- end }} +{{- /* user-scheduler-serviceaccount ServiceAccount */}} +{{- define "jupyterhub.user-scheduler-serviceaccount.fullname" -}} + {{- if .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.create }} + {{- .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.name | default (include "jupyterhub.user-scheduler-deploy.fullname" .) }} + {{- else }} + {{- .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.name | default "default" }} + {{- end }} +{{- end }} + {{- /* user-scheduler leader election lock resource */}} {{- define "jupyterhub.user-scheduler-lock.fullname" -}} {{- include "jupyterhub.user-scheduler-deploy.fullname" . }}-lock @@ -153,6 +182,15 @@ {{- include "jupyterhub.fullname.dash" . }}hook-image-awaiter {{- end }} +{{- /* image-awaiter-serviceaccount ServiceAccount */}} +{{- define "jupyterhub.hook-image-awaiter-serviceaccount.fullname" -}} + {{- if .Values.apps.jupyterhub.prePuller.hook.serviceAccount.create }} + {{- .Values.apps.jupyterhub.prePuller.hook.serviceAccount.name | default (include "jupyterhub.hook-image-awaiter.fullname" .) }} + {{- else }} + {{- .Values.apps.jupyterhub.prePuller.hook.serviceAccount.name | default "default" }} + {{- end }} +{{- end }} + {{- /* hook-image-puller DaemonSet */}} {{- define "jupyterhub.hook-image-puller.fullname" -}} {{- include "jupyterhub.fullname.dash" . }}hook-image-puller @@ -210,6 +248,15 @@ {{- end }} {{- end }} +{{- /* image-puller Priority */}} +{{- define "jupyterhub.image-puller-priority.fullname" -}} + {{- if (include "jupyterhub.fullname" .) }} + {{- include "jupyterhub.fullname.dash" . }}image-puller + {{- else }} + {{- .Release.Name }}-image-puller-priority + {{- end }} +{{- end }} + {{- /* user-scheduler's registered name */}} {{- define "jupyterhub.user-scheduler.fullname" -}} {{- if (include "jupyterhub.fullname" .) }} @@ -231,6 +278,7 @@ fullname: {{ include "jupyterhub.fullname" . | quote }} fullname-dash: {{ include "jupyterhub.fullname.dash" . | quote }} hub: {{ include "jupyterhub.hub.fullname" . | quote }} +hub-serviceaccount: {{ include "jupyterhub.hub-serviceaccount.fullname" . | quote }} hub-existing-secret: {{ include "jupyterhub.hub-existing-secret.fullname" . | quote }} hub-existing-secret-or-default: {{ include "jupyterhub.hub-existing-secret-or-default.fullname" . | quote }} hub-pvc: {{ include "jupyterhub.hub-pvc.fullname" . | quote }} @@ -241,10 +289,14 @@ proxy-public: {{ include "jupyterhub.proxy-public.fullname" . | quote }} proxy-public-tls: {{ include "jupyterhub.proxy-public-tls.fullname" . | quote }} proxy-public-manual-tls: {{ include "jupyterhub.proxy-public-manual-tls.fullname" . | quote }} autohttps: {{ include "jupyterhub.autohttps.fullname" . | quote }} +autohttps-serviceaccount: {{ include "jupyterhub.autohttps-serviceaccount.fullname" . | quote }} user-scheduler-deploy: {{ include "jupyterhub.user-scheduler-deploy.fullname" . | quote }} +user-scheduler-serviceaccount: {{ include "jupyterhub.user-scheduler-serviceaccount.fullname" . | quote }} user-scheduler-lock: {{ include "jupyterhub.user-scheduler-lock.fullname" . | quote }} user-placeholder: {{ include "jupyterhub.user-placeholder.fullname" . | quote }} +image-puller-priority: {{ include "jupyterhub.image-puller-priority.fullname" . | quote }} hook-image-awaiter: {{ include "jupyterhub.hook-image-awaiter.fullname" . | quote }} +hook-image-awaiter-serviceaccount: {{ include "jupyterhub.hook-image-awaiter-serviceaccount.fullname" . | quote }} hook-image-puller: {{ include "jupyterhub.hook-image-puller.fullname" . | quote }} continuous-image-puller: {{ include "jupyterhub.continuous-image-puller.fullname" . | quote }} singleuser: {{ include "jupyterhub.singleuser.fullname" . | quote }} diff --git a/applications/jupyterhub/deploy/templates/_helpers-netpol.tpl b/applications/jupyterhub/deploy/templates/_helpers-netpol.tpl new file mode 100644 index 000000000..4075569ef --- /dev/null +++ b/applications/jupyterhub/deploy/templates/_helpers-netpol.tpl @@ -0,0 +1,101 @@ +{{- /* + This named template renders egress rules for NetworkPolicy resources based on + common configuration. + + It is rendering based on the `egressAllowRules` and `egress` keys of the + passed networkPolicy config object. Each flag set to true under + `egressAllowRules` is rendered to a egress rule that next to any custom user + defined rules from the `egress` config. + + This named template needs to render based on a specific networkPolicy + resource, but also needs access to the root context. Due to that, it + accepts a list as its scope, where the first element is supposed to be the + root context and the second element is supposed to be the networkPolicy + configuration object. + + As an example, this is how you would render this named template from a + NetworkPolicy resource under its egress: + + egress: + # other rules here... + + {{- with (include "jupyterhub.networkPolicy.renderEgressRules" (list . .Values.apps.jupyterhub.hub.networkPolicy)) }} + {{- . | nindent 4 }} + {{- end }} + + Note that the reference to privateIPs and nonPrivateIPs relate to + https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses. +*/}} + +{{- define "jupyterhub.networkPolicy.renderEgressRules" -}} +{{- $root := index . 0 }} +{{- $netpol := index . 1 }} +{{- if or (or $netpol.egressAllowRules.dnsPortsCloudMetadataServer $netpol.egressAllowRules.dnsPortsKubeSystemNamespace) $netpol.egressAllowRules.dnsPortsPrivateIPs }} +- ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + to: + {{- if $netpol.egressAllowRules.dnsPortsCloudMetadataServer }} + # Allow outbound connections to DNS ports on the cloud metadata server + - ipBlock: + cidr: {{ $root.Values.apps.jupyterhub.singleuser.cloudMetadata.ip }}/32 + {{- end }} + {{- if $netpol.egressAllowRules.dnsPortsKubeSystemNamespace }} + # Allow outbound connections to DNS ports on pods in the kube-system + # namespace + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + {{- end }} + {{- if $netpol.egressAllowRules.dnsPortsPrivateIPs }} + # Allow outbound connections to DNS ports on destinations in the private IP + # ranges + - ipBlock: + cidr: 10.0.0.0/8 + - ipBlock: + cidr: 172.16.0.0/12 + - ipBlock: + cidr: 192.168.0.0/16 + {{- end }} +{{- end }} + +{{- if $netpol.egressAllowRules.nonPrivateIPs }} +# Allow outbound connections to non-private IP ranges +- to: + - ipBlock: + cidr: 0.0.0.0/0 + except: + # As part of this rule: + # - don't allow outbound connections to private IPs + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + # - don't allow outbound connections to the cloud metadata server + - {{ $root.Values.apps.jupyterhub.singleuser.cloudMetadata.ip }}/32 +{{- end }} + +{{- if $netpol.egressAllowRules.privateIPs }} +# Allow outbound connections to private IP ranges +- to: + - ipBlock: + cidr: 10.0.0.0/8 + - ipBlock: + cidr: 172.16.0.0/12 + - ipBlock: + cidr: 192.168.0.0/16 +{{- end }} + +{{- if $netpol.egressAllowRules.cloudMetadataServer }} +# Allow outbound connections to the cloud metadata server +- to: + - ipBlock: + cidr: {{ $root.Values.apps.jupyterhub.singleuser.cloudMetadata.ip }}/32 +{{- end }} + +{{- with $netpol.egress }} +# Allow outbound connections based on user specified rules +{{ . | toYaml }} +{{- end }} +{{- end }} diff --git a/applications/jupyterhub/deploy/templates/_helpers.tpl b/applications/jupyterhub/deploy/templates/_helpers.tpl index efea86d1d..a20236395 100755 --- a/applications/jupyterhub/deploy/templates/_helpers.tpl +++ b/applications/jupyterhub/deploy/templates/_helpers.tpl @@ -12,7 +12,7 @@ When you ask a helper to render its content, one often forward the current scope to the helper in order to allow it to access .Release.Name, - .Values.apps.jupyterhub.rbac.enabled and similar values. + .Values.apps.jupyterhub.rbac.create and similar values. #### Example - Passing the current scope {{ include "jupyterhub.commonLabels" . }} @@ -180,8 +180,51 @@ component: {{ include "jupyterhub.componentLabel" . }} Augments passed .pullSecrets with $.Values.apps.jupyterhub.imagePullSecrets */}} {{- define "jupyterhub.imagePullSecrets" -}} + {{- /* + We have implemented a trick to allow a parent chart depending on this + chart to call this named templates. + + Caveats and notes: + + 1. While parent charts can reference these, grandparent charts can't. + 2. Parent charts must not use an alias for this chart. + 3. There is no failsafe workaround to above due to + https://github.com/helm/helm/issues/9214. + 4. .Chart is of its own type (*chart.Metadata) and needs to be casted + using "toYaml | fromYaml" in order to be able to use normal helm + template functions on it. + */}} + {{- $jupyterhub_values := .root.Values.apps.jupyterhub.}} + {{- if ne .root.Chart.Name "jupyterhub" }} + {{- if .root.Values.apps.jupyterhub.jupyterhub }} + {{- $jupyterhub_values = .root.Values.apps.jupyterhub.jupyterhub }} + {{- end }} + {{- end }} + {{- /* Populate $_.list with all relevant entries */}} + {{- $_ := dict "list" (concat .image.pullSecrets $jupyterhub_values.imagePullSecrets | uniq) }} + {{- if and $jupyterhub_values.imagePullSecret.create $jupyterhub_values.imagePullSecret.automaticReferenceInjection }} + {{- $__ := set $_ "list" (append $_.list (include "jupyterhub.image-pull-secret.fullname" .root) | uniq) }} + {{- end }} + {{- /* Decide if something should be written */}} + {{- if not (eq ($_.list | toJson) "[]") }} + + {{- /* Process the $_.list where strings become dicts with a name key and the + strings become the name keys' values into $_.res */}} + {{- $_ := set $_ "res" list }} + {{- range $_.list }} + {{- if eq (typeOf .) "string" }} + {{- $__ := set $_ "res" (append $_.res (dict "name" .)) }} + {{- else }} + {{- $__ := set $_ "res" (append $_.res .) }} + {{- end }} + {{- end }} + + {{- /* Write the results */}} + {{- $_.res | toJson }} + + {{- end }} {{- end }} {{- /* @@ -339,3 +382,21 @@ limits: {{- print "\n\nextraFiles entries (" $file_key ") must only contain one of the fields: 'data', 'stringData', and 'binaryData'." | fail }} {{- end }} {{- end }} + +{{- /* + jupyterhub.chart-version-to-git-ref: + Renders a valid git reference from a chartpress generated version string. + In practice, either a git tag or a git commit hash will be returned. + + - The version string will follow a chartpress pattern, see + https://github.com/jupyterhub/chartpress#examples-chart-versions-and-image-tags. + + - The regexReplaceAll function is a sprig library function, see + https://masterminds.github.io/sprig/strings.html. + + - The regular expression is in golang syntax, but \d had to become \\d for + example. +*/}} +{{- define "jupyterhub.chart-version-to-git-ref" -}} +{{- regexReplaceAll ".*[.-]n\\d+[.]h(.*)" . "${1}" }} +{{- end }} diff --git a/applications/jupyterhub/deploy/templates/hub/configmap.yaml b/applications/jupyterhub/deploy/templates/hub/configmap.yaml index c913f678b..f52feb6a8 100755 --- a/applications/jupyterhub/deploy/templates/hub/configmap.yaml +++ b/applications/jupyterhub/deploy/templates/hub/configmap.yaml @@ -29,5 +29,6 @@ data: */}} checksum_hook-image-puller: {{ include "jupyterhub.imagePuller.daemonset.hook.checksum" . | quote }} + # EDIT: CLOUDHARNESS allvalues.yaml: | {{- .Values | toYaml | nindent 4 }} \ No newline at end of file diff --git a/applications/jupyterhub/deploy/templates/hub/deployment.yaml b/applications/jupyterhub/deploy/templates/hub/deployment.yaml index 82132c628..d105eccaf 100755 --- a/applications/jupyterhub/deploy/templates/hub/deployment.yaml +++ b/applications/jupyterhub/deploy/templates/hub/deployment.yaml @@ -5,6 +5,9 @@ metadata: labels: {{- include "jupyterhub.labels" . | nindent 4 }} spec: + {{- if typeIs "int" .Values.apps.jupyterhub.hub.revisionHistoryLimit }} + revisionHistoryLimit: {{ .Values.apps.jupyterhub.hub.revisionHistoryLimit }} + {{- end }} replicas: 1 selector: matchLabels: @@ -30,11 +33,14 @@ spec: {{- . | toYaml | nindent 8 }} {{- end }} spec: -{{ include "deploy_utils.etcHosts" . | indent 6 }} +{{ include "deploy_utils.etcHosts" . | indent 6 }} # EDIT: CLOUDHARNESS {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} priorityClassName: {{ include "jupyterhub.priority.fullname" . }} {{- end }} - nodeSelector: {{ toJson .Values.apps.jupyterhub.hub.nodeSelector }} + {{- with .Values.apps.jupyterhub.hub.nodeSelector }} + nodeSelector: + {{- . | toYaml | nindent 8 }} + {{- end }} {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.hub.tolerations }} tolerations: {{- . | toYaml | nindent 8 }} @@ -44,7 +50,7 @@ spec: - name: config configMap: name: {{ include "jupyterhub.hub.fullname" . }} - {{- /* This is needed by cloudharness libraries */}} + {{- /* EDIT: CLOUDHARNESS This is needed by cloudharness libraries */}} - name: cloudharness-allvalues configMap: name: cloudharness-allvalues @@ -82,11 +88,13 @@ spec: persistentVolumeClaim: claimName: {{ include "jupyterhub.hub-pvc.fullname" . }} {{- end }} - {{- if .Values.apps.jupyterhub.rbac.enabled }} - serviceAccountName: {{ include "jupyterhub.hub.fullname" . }} + {{- with include "jupyterhub.hub-serviceaccount.fullname" . }} + serviceAccountName: {{ . }} {{- end }} + {{- with .Values.apps.jupyterhub.hub.podSecurityContext }} securityContext: - fsGroup: {{ .Values.apps.jupyterhub.hub.fsGid }} + {{- . | toYaml | nindent 8 }} + {{- end }} {{- with include "jupyterhub.imagePullSecrets" (dict "root" . "image" .Values.apps.jupyterhub.hub.image) }} imagePullSecrets: {{ . }} {{- end }} @@ -153,14 +161,14 @@ spec: name: config - mountPath: /usr/local/etc/jupyterhub/secret/ name: secret - - name: cloudharness-allvalues + - name: cloudharness-allvalues # EDIT: CLOUDHARNESS START mountPath: /opt/cloudharness/resources/allvalues.yaml subPath: allvalues.yaml {{- if .Values.apps.accounts }} - name: cloudharness-kc-accounts mountPath: /opt/cloudharness/resources/auth readOnly: true - {{- end }} + {{- end }} # EDIT: CLOUDHARNESS END {{- if (include "jupyterhub.hub-existing-secret.fullname" .) }} - mountPath: /usr/local/etc/jupyterhub/existing-secret/ name: existing-secret diff --git a/applications/jupyterhub/deploy/templates/hub/netpol.yaml b/applications/jupyterhub/deploy/templates/hub/netpol.yaml index 9a7a6bc12..d9508e20c 100755 --- a/applications/jupyterhub/deploy/templates/hub/netpol.yaml +++ b/applications/jupyterhub/deploy/templates/hub/netpol.yaml @@ -61,31 +61,24 @@ spec: egress: # hub --> proxy - - ports: - - port: 8001 - to: + - to: - podSelector: matchLabels: {{- $_ := merge (dict "componentLabel" "proxy") . }} {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} + ports: + - port: 8001 + # hub --> singleuser-server - - ports: - - port: 8888 - to: + - to: - podSelector: matchLabels: {{- $_ := merge (dict "componentLabel" "singleuser-server") . }} {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} + ports: + - port: 8888 - # hub --> Kubernetes internal DNS - - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - {{- with .Values.apps.jupyterhub.hub.networkPolicy.egress }} - # hub --> depends, but the default is everything - {{- . | toYaml | nindent 4 }} + {{- with (include "jupyterhub.networkPolicy.renderEgressRules" (list . .Values.apps.jupyterhub.hub.networkPolicy)) }} + {{- . | nindent 4 }} {{- end }} {{- end }} diff --git a/applications/jupyterhub/deploy/templates/hub/pdb.yaml b/applications/jupyterhub/deploy/templates/hub/pdb.yaml index 855609d41..bb6c7b16d 100755 --- a/applications/jupyterhub/deploy/templates/hub/pdb.yaml +++ b/applications/jupyterhub/deploy/templates/hub/pdb.yaml @@ -1,9 +1,5 @@ {{- if .Values.apps.jupyterhub.hub.pdb.enabled -}} -{{- if .Capabilities.APIVersions.Has "policy/v1" }} apiVersion: policy/v1 -{{- else }} -apiVersion: policy/v1beta1 -{{- end }} kind: PodDisruptionBudget metadata: name: {{ include "jupyterhub.hub.fullname" . }} diff --git a/applications/jupyterhub/deploy/templates/hub/rbac.yaml b/applications/jupyterhub/deploy/templates/hub/rbac.yaml index 738daab15..1b689af49 100755 --- a/applications/jupyterhub/deploy/templates/hub/rbac.yaml +++ b/applications/jupyterhub/deploy/templates/hub/rbac.yaml @@ -1,15 +1,4 @@ -{{- if .Values.apps.jupyterhub.rbac.enabled -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "jupyterhub.hub.fullname" . }} - {{- with .Values.apps.jupyterhub.hub.serviceAccount.annotations }} - annotations: - {{- . | toYaml | nindent 4 }} - {{- end }} - labels: - {{- include "jupyterhub.labels" . | nindent 4 }} ---- +{{- if .Values.apps.jupyterhub.rbac.create -}} kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -32,7 +21,7 @@ metadata: {{- include "jupyterhub.labels" . | nindent 4 }} subjects: - kind: ServiceAccount - name: {{ include "jupyterhub.hub.fullname" . }} + name: {{ include "jupyterhub.hub-serviceaccount.fullname" . }} namespace: "{{ .Release.Namespace }}" roleRef: kind: Role diff --git a/applications/jupyterhub/deploy/templates/hub/serviceaccount.yaml b/applications/jupyterhub/deploy/templates/hub/serviceaccount.yaml new file mode 100644 index 000000000..817ed661f --- /dev/null +++ b/applications/jupyterhub/deploy/templates/hub/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.apps.jupyterhub.hub.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "jupyterhub.hub-serviceaccount.fullname" . }} + {{- with .Values.apps.jupyterhub.hub.serviceAccount.annotations }} + annotations: + {{- . | toYaml | nindent 4 }} + {{- end }} + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} +{{- end }} diff --git a/applications/jupyterhub/deploy/templates/image-pull-secret.yaml b/applications/jupyterhub/deploy/templates/image-pull-secret.yaml new file mode 100644 index 000000000..b7544db72 --- /dev/null +++ b/applications/jupyterhub/deploy/templates/image-pull-secret.yaml @@ -0,0 +1,15 @@ +{{- if .Values.apps.jupyterhub.imagePullSecret.create }} +kind: Secret +apiVersion: v1 +metadata: + name: {{ include "jupyterhub.image-pull-secret.fullname" . }} + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation + "helm.sh/hook-weight": "-20" +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: {{ include "jupyterhub.dockerconfigjson" . }} +{{- end }} diff --git a/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl b/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl index e16fd1a9e..528345c08 100644 --- a/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl +++ b/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl @@ -34,6 +34,9 @@ spec: type: RollingUpdate rollingUpdate: maxUnavailable: 100% + {{- if typeIs "int" .Values.apps.jupyterhub.prePuller.revisionHistoryLimit }} + revisionHistoryLimit: {{ .Values.apps.jupyterhub.prePuller.revisionHistoryLimit }} + {{- end }} template: metadata: labels: @@ -44,13 +47,17 @@ spec: {{- end }} spec: {{- /* - continuous-image-puller pods are made evictable to save on the k8s pods - per node limit all k8s clusters have. + image-puller pods are made evictable to save on the k8s pods + per node limit all k8s clusters have and have a higher priority + than user-placeholder pods that could block an entire node. */}} - {{- if and (not .hook) .Values.apps.jupyterhub.scheduling.podPriority.enabled }} - priorityClassName: {{ include "jupyterhub.user-placeholder-priority.fullname" . }} + {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} + priorityClassName: {{ include "jupyterhub.image-puller-priority.fullname" . }} + {{- end }} + {{- with .Values.apps.jupyterhub.singleuser.nodeSelector }} + nodeSelector: + {{- . | toYaml | nindent 8 }} {{- end }} - nodeSelector: {{ toJson .Values.apps.jupyterhub.singleuser.nodeSelector }} {{- with concat .Values.apps.jupyterhub.scheduling.userPods.tolerations .Values.apps.jupyterhub.singleuser.extraTolerations .Values.apps.jupyterhub.prePuller.extraTolerations }} tolerations: {{- . | toYaml | nindent 8 }} @@ -127,6 +134,7 @@ spec: {{- /* --- Conditionally pull profileList images --- */}} {{- if .Values.apps.jupyterhub.prePuller.pullProfileListImages }} {{- range $k, $container := .Values.apps.jupyterhub.singleuser.profileList }} + {{- /* profile's kubespawner_override */}} {{- if $container.kubespawner_override }} {{- if $container.kubespawner_override.image }} - name: image-pull-singleuser-profilelist-{{ $k }} @@ -145,13 +153,15 @@ spec: {{- end }} {{- end }} {{- end }} - {{- end }} - {{- end }} - - {{- /* --- Pull extra images --- */}} - {{- range $k, $v := .Values.apps.jupyterhub.prePuller.extraImages }} - - name: image-pull-{{ $k }} - image: {{ $v.name }}:{{ $v.tag }} + {{- /* kubespawner_override in profile's profile_options */}} + {{- if $container.profile_options }} + {{- range $option, $option_spec := $container.profile_options }} + {{- if $option_spec.choices }} + {{- range $choice, $choice_spec := $option_spec.choices }} + {{- if $choice_spec.kubespawner_override }} + {{- if $choice_spec.kubespawner_override.image }} + - name: image-pull-profile-{{ $k }}-option-{{ $option }}-{{ $choice }} + image: {{ $choice_spec.kubespawner_override.image }} command: - /bin/sh - -c @@ -163,13 +173,20 @@ spec: {{- with $.Values.apps.jupyterhub.prePuller.containerSecurityContext }} securityContext: {{- . | toYaml | nindent 12 }} - {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} {{- end }} - {{- /* --- Pull CloudHarness tasks images --- */}} - {{- range $k, $v := ( index .Values "task-images" ) }} - - name: image-pull-{{ $k | replace "-" "" }} - image: {{ $v }} + {{- /* --- Pull extra images --- */}} + {{- range $k, $v := .Values.apps.jupyterhub.prePuller.extraImages }} + - name: image-pull-{{ $k }} + image: {{ $v.name }}:{{ $v.tag }} command: - /bin/sh - -c diff --git a/applications/jupyterhub/deploy/templates/image-puller/job.yaml b/applications/jupyterhub/deploy/templates/image-puller/job.yaml index bdd9f63c0..cc6db3ecf 100755 --- a/applications/jupyterhub/deploy/templates/image-puller/job.yaml +++ b/applications/jupyterhub/deploy/templates/image-puller/job.yaml @@ -28,16 +28,22 @@ spec: labels: {{- /* Changes here will cause the Job to restart the pods. */}} {{- include "jupyterhub.matchLabels" . | nindent 8 }} + {{- with .Values.apps.jupyterhub.prePuller.labels }} + {{- . | toYaml | nindent 8 }} + {{- end }} {{- with .Values.apps.jupyterhub.prePuller.annotations }} annotations: {{- . | toYaml | nindent 8 }} {{- end }} spec: restartPolicy: Never - {{- if .Values.apps.jupyterhub.rbac.enabled }} - serviceAccountName: {{ include "jupyterhub.hook-image-awaiter.fullname" . }} + {{- with include "jupyterhub.hook-image-awaiter-serviceaccount.fullname" . }} + serviceAccountName: {{ . }} + {{- end }} + {{- with .Values.apps.jupyterhub.prePuller.hook.nodeSelector }} + nodeSelector: + {{- . | toYaml | nindent 8 }} {{- end }} - nodeSelector: {{ toJson .Values.apps.jupyterhub.prePuller.hook.nodeSelector }} {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.prePuller.hook.tolerations }} tolerations: {{- . | toYaml | nindent 8 }} @@ -58,6 +64,7 @@ spec: - -api-server-address=https://kubernetes.default.svc:$(KUBERNETES_SERVICE_PORT) - -namespace={{ .Release.Namespace }} - -daemonset={{ include "jupyterhub.hook-image-puller.fullname" . }} + - -pod-scheduling-wait-duration={{ .Values.apps.jupyterhub.prePuller.hook.podSchedulingWaitDuration }} {{- with .Values.apps.jupyterhub.prePuller.hook.containerSecurityContext }} securityContext: {{- . | toYaml | nindent 12 }} diff --git a/applications/jupyterhub/deploy/templates/image-puller/priorityclass.yaml b/applications/jupyterhub/deploy/templates/image-puller/priorityclass.yaml new file mode 100644 index 000000000..1a3fca335 --- /dev/null +++ b/applications/jupyterhub/deploy/templates/image-puller/priorityclass.yaml @@ -0,0 +1,18 @@ +{{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} +{{- if or .Values.apps.jupyterhub.prePuller.hook.enabled .Values.apps.jupyterhub.prePuller.continuous.enabled -}} +apiVersion: scheduling.k8s.io/v1 +kind: PriorityClass +metadata: + name: {{ include "jupyterhub.image-puller-priority.fullname" . }} + annotations: + meta.helm.sh/release-name: "{{ .Release.Name }}" + meta.helm.sh/release-namespace: "{{ .Release.Namespace }}" + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} +value: {{ .Values.apps.jupyterhub.scheduling.podPriority.imagePullerPriority }} +globalDefault: false +description: >- + Enables [hook|continuous]-image-puller pods to fit on nodes even though they + are clogged by user-placeholder pods, while not evicting normal user pods. +{{- end }} +{{- end }} diff --git a/applications/jupyterhub/deploy/templates/image-puller/rbac.yaml b/applications/jupyterhub/deploy/templates/image-puller/rbac.yaml index 95c86ddf0..5946896b6 100755 --- a/applications/jupyterhub/deploy/templates/image-puller/rbac.yaml +++ b/applications/jupyterhub/deploy/templates/image-puller/rbac.yaml @@ -1,29 +1,8 @@ {{- /* Permissions to be used by the hook-image-awaiter job */}} -{{- if .Values.apps.jupyterhub.rbac.enabled }} -{{- if (include "jupyterhub.imagePuller.daemonset.hook.install" .) }} -{{- /* -This service account... -*/ -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "jupyterhub.hook-image-awaiter.fullname" . }} - labels: - {{- include "jupyterhub.labels" . | nindent 4 }} - hub.jupyter.org/deletable: "true" - annotations: - "helm.sh/hook": pre-install,pre-upgrade - "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded - "helm.sh/hook-weight": "0" - {{- with .Values.apps.jupyterhub.prePuller.hook.serviceAccount.annotations }} - {{- . | toYaml | nindent 4 }} - {{- end }} ---- -{{- /* -... will be used by this role... -*/}} +{{- if .Values.apps.jupyterhub.rbac.create -}} +{{- if (include "jupyterhub.imagePuller.daemonset.hook.install" .) -}} kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -56,7 +35,7 @@ metadata: "helm.sh/hook-weight": "0" subjects: - kind: ServiceAccount - name: {{ include "jupyterhub.hook-image-awaiter.fullname" . }} + name: {{ include "jupyterhub.hook-image-awaiter-serviceaccount.fullname" . }} namespace: "{{ .Release.Namespace }}" roleRef: kind: Role diff --git a/applications/jupyterhub/deploy/templates/image-puller/serviceaccount.yaml b/applications/jupyterhub/deploy/templates/image-puller/serviceaccount.yaml new file mode 100644 index 000000000..2e5fa7286 --- /dev/null +++ b/applications/jupyterhub/deploy/templates/image-puller/serviceaccount.yaml @@ -0,0 +1,21 @@ +{{- /* +ServiceAccount for the pre-puller hook's image-awaiter-job +*/}} +{{- if .Values.apps.jupyterhub.prePuller.hook.serviceAccount.create -}} +{{- if (include "jupyterhub.imagePuller.daemonset.hook.install" .) -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "jupyterhub.hook-image-awaiter-serviceaccount.fullname" . }} + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} + hub.jupyter.org/deletable: "true" + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + "helm.sh/hook-weight": "0" + {{- with .Values.apps.jupyterhub.prePuller.hook.serviceAccount.annotations }} + {{- . | toYaml | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/_README.txt b/applications/jupyterhub/deploy/templates/proxy/autohttps/_README.txt deleted file mode 100755 index 08bd7bbab..000000000 --- a/applications/jupyterhub/deploy/templates/proxy/autohttps/_README.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Automatic HTTPS Terminator - -This directory has Kubernetes objects for automatic Let's Encrypt Support. -When enabled, we create a new deployment object that has an nginx-ingress -and kube-lego container in it. This is responsible for requesting, -storing and renewing certificates as needed from Let's Encrypt. - -The only change required outside of this directory is in the `proxy-public` -service, which targets different hubs based on automatic HTTPS status. \ No newline at end of file diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/configmap.yaml b/applications/jupyterhub/deploy/templates/proxy/autohttps/configmap.yaml deleted file mode 100755 index 8d71a9716..000000000 --- a/applications/jupyterhub/deploy/templates/proxy/autohttps/configmap.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- $HTTPS := (and .Values.apps.jupyterhub.proxy.https.hosts .Values.apps.jupyterhub.proxy.https.enabled) }} -{{- $autoHTTPS := (and $HTTPS (eq .Values.apps.jupyterhub.proxy.https.type "letsencrypt")) }} -{{- if $autoHTTPS -}} -{{- $_ := .Values.apps.jupyterhub.proxy.https.letsencrypt.contactEmail | required "proxy.https.letsencrypt.contactEmail is a required field" -}} - -# This configmap contains Traefik configuration files to be mounted. -# - traefik.yaml will only be read during startup (static configuration) -# - dynamic.yaml will be read on change (dynamic configuration) -# -# ref: https://docs.traefik.io/getting-started/configuration-overview/ -# -# The configuration files are first rendered with Helm templating to large YAML -# strings. Then we use the fromYAML function on these strings to get an object, -# that we in turn merge with user provided extra configuration. -# -kind: ConfigMap -apiVersion: v1 -metadata: - name: {{ include "jupyterhub.autohttps.fullname" . }} - labels: - {{- include "jupyterhub.labels" . | nindent 4 }} -data: - traefik.yaml: | - {{- include "jupyterhub.traefik.yaml" . | fromYaml | merge .Values.apps.jupyterhub.proxy.traefik.extraStaticConfig | toYaml | nindent 4 }} - dynamic.yaml: | - {{- include "jupyterhub.dynamic.yaml" . | fromYaml | merge .Values.apps.jupyterhub.proxy.traefik.extraDynamicConfig | toYaml | nindent 4 }} - -{{- end }} diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/deployment.yaml b/applications/jupyterhub/deploy/templates/proxy/autohttps/deployment.yaml deleted file mode 100755 index fcb062fd0..000000000 --- a/applications/jupyterhub/deploy/templates/proxy/autohttps/deployment.yaml +++ /dev/null @@ -1,141 +0,0 @@ -{{- $HTTPS := (and .Values.apps.jupyterhub.proxy.https.hosts .Values.apps.jupyterhub.proxy.https.enabled) }} -{{- $autoHTTPS := (and $HTTPS (eq .Values.apps.jupyterhub.proxy.https.type "letsencrypt")) }} -{{- if $autoHTTPS -}} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "jupyterhub.autohttps.fullname" . }} - labels: - {{- include "jupyterhub.labels" . | nindent 4 }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "jupyterhub.matchLabels" . | nindent 6 }} - template: - metadata: - labels: - {{- include "jupyterhub.matchLabels" . | nindent 8 }} - hub.jupyter.org/network-access-proxy-http: "true" - {{- with .Values.apps.jupyterhub.proxy.traefik.labels }} - {{- . | toYaml | nindent 8 }} - {{- end }} - annotations: - # Only force a restart through a change to this checksum when the static - # configuration is changed, as the dynamic can be updated after start. - # Any disruptions to this deployment impacts everything, it is the - # entrypoint of all network traffic. - checksum/static-config: {{ include "jupyterhub.traefik.yaml" . | fromYaml | merge .Values.apps.jupyterhub.proxy.traefik.extraStaticConfig | toYaml | sha256sum }} - spec: - {{- if .Values.apps.jupyterhub.rbac.enabled }} - serviceAccountName: {{ include "jupyterhub.autohttps.fullname" . }} - {{- end }} - {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} - priorityClassName: {{ include "jupyterhub.priority.fullname" . }} - {{- end }} - nodeSelector: {{ toJson .Values.apps.jupyterhub.proxy.traefik.nodeSelector }} - {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.proxy.traefik.tolerations }} - tolerations: - {{- . | toYaml | nindent 8 }} - {{- end }} - {{- include "jupyterhub.coreAffinity" . | nindent 6 }} - volumes: - - name: certificates - emptyDir: {} - - name: traefik-config - configMap: - name: {{ include "jupyterhub.autohttps.fullname" . }} - {{- with .Values.apps.jupyterhub.proxy.traefik.extraVolumes }} - {{- . | toYaml | nindent 8 }} - {{- end }} - {{- with include "jupyterhub.imagePullSecrets" (dict "root" . "image" .Values.apps.jupyterhub.proxy.traefik.image) }} - imagePullSecrets: {{ . }} - {{- end }} - initContainers: - - name: load-acme - image: "{{ .Values.apps.jupyterhub.proxy.secretSync.image.name }}:{{ .Values.apps.jupyterhub.proxy.secretSync.image.tag }}" - {{- with .Values.apps.jupyterhub.proxy.secretSync.image.pullPolicy }} - imagePullPolicy: {{ . }} - {{- end }} - args: - - load - - {{ include "jupyterhub.proxy-public-tls.fullname" . }} - - acme.json - - /etc/acme/acme.json - env: - # We need this to get logs immediately - - name: PYTHONUNBUFFERED - value: "True" - {{- with .Values.apps.jupyterhub.proxy.traefik.extraEnv }} - {{- include "jupyterhub.extraEnv" . | nindent 12 }} - {{- end }} - volumeMounts: - - name: certificates - mountPath: /etc/acme - {{- with .Values.apps.jupyterhub.proxy.secretSync.containerSecurityContext }} - securityContext: - {{- . | toYaml | nindent 12 }} - {{- end }} - containers: - - name: traefik - image: "{{ .Values.apps.jupyterhub.proxy.traefik.image.name }}:{{ .Values.apps.jupyterhub.proxy.traefik.image.tag }}" - {{- with .Values.apps.jupyterhub.proxy.traefik.image.pullPolicy }} - imagePullPolicy: {{ . }} - {{- end }} - {{- with .Values.apps.jupyterhub.proxy.traefik.resources }} - resources: - {{- . | toYaml | nindent 12 }} - {{- end }} - ports: - - name: http - containerPort: 8080 - - name: https - containerPort: 8443 - {{- with .Values.apps.jupyterhub.proxy.traefik.extraPorts }} - {{- . | toYaml | nindent 12 }} - {{- end }} - volumeMounts: - - name: traefik-config - mountPath: /etc/traefik - - name: certificates - mountPath: /etc/acme - {{- with .Values.apps.jupyterhub.proxy.traefik.extraVolumeMounts }} - {{- . | toYaml | nindent 12 }} - {{- end }} - {{- with .Values.apps.jupyterhub.proxy.traefik.extraEnv }} - env: - {{- include "jupyterhub.extraEnv" . | nindent 12 }} - {{- end }} - {{- with .Values.apps.jupyterhub.proxy.traefik.containerSecurityContext }} - securityContext: - {{- . | toYaml | nindent 12 }} - {{- end }} - - name: secret-sync - image: "{{ .Values.apps.jupyterhub.proxy.secretSync.image.name }}:{{ .Values.apps.jupyterhub.proxy.secretSync.image.tag }}" - {{- with .Values.apps.jupyterhub.proxy.secretSync.image.pullPolicy }} - imagePullPolicy: {{ . }} - {{- end }} - args: - - watch-save - - --label=app={{ include "jupyterhub.appLabel" . }} - - --label=release={{ .Release.Name }} - - --label=chart={{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - - --label=heritage=secret-sync - - {{ include "jupyterhub.proxy-public-tls.fullname" . }} - - acme.json - - /etc/acme/acme.json - env: - # We need this to get logs immediately - - name: PYTHONUNBUFFERED - value: "True" - volumeMounts: - - name: certificates - mountPath: /etc/acme - {{- with .Values.apps.jupyterhub.proxy.secretSync.containerSecurityContext }} - securityContext: - {{- . | toYaml | nindent 12 }} - {{- end }} - {{- with .Values.apps.jupyterhub.proxy.traefik.extraPodSpec }} - {{- . | toYaml | nindent 6 }} - {{- end }} -{{- end }} diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/rbac.yaml b/applications/jupyterhub/deploy/templates/proxy/autohttps/rbac.yaml deleted file mode 100755 index ea43b6726..000000000 --- a/applications/jupyterhub/deploy/templates/proxy/autohttps/rbac.yaml +++ /dev/null @@ -1,40 +0,0 @@ -{{- $HTTPS := (and .Values.apps.jupyterhub.proxy.https.hosts .Values.apps.jupyterhub.proxy.https.enabled) }} -{{- $autoHTTPS := (and $HTTPS (eq .Values.apps.jupyterhub.proxy.https.type "letsencrypt")) }} -{{- if (and $autoHTTPS .Values.apps.jupyterhub.rbac.enabled) -}} -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ include "jupyterhub.autohttps.fullname" . }} - labels: - {{- include "jupyterhub.labels" . | nindent 4 }} - {{- with .Values.apps.jupyterhub.proxy.traefik.serviceAccount.annotations }} - annotations: - {{- . | toYaml | nindent 4 }} - {{- end }} -rules: -- apiGroups: [""] - resources: ["secrets"] - verbs: ["get", "patch", "list", "create"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ include "jupyterhub.autohttps.fullname" . }} - labels: - {{- include "jupyterhub.labels" . | nindent 4 }} -subjects: -- kind: ServiceAccount - name: {{ include "jupyterhub.autohttps.fullname" . }} - apiGroup: -roleRef: - kind: Role - name: {{ include "jupyterhub.autohttps.fullname" . }} - apiGroup: rbac.authorization.k8s.io ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "jupyterhub.autohttps.fullname" . }} - labels: - {{- include "jupyterhub.labels" . | nindent 4 }} -{{- end }} diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/service.yaml b/applications/jupyterhub/deploy/templates/proxy/autohttps/service.yaml deleted file mode 100755 index d57c135dd..000000000 --- a/applications/jupyterhub/deploy/templates/proxy/autohttps/service.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- $HTTPS := (and .Values.apps.jupyterhub.proxy.https.hosts .Values.apps.jupyterhub.proxy.https.enabled) }} -{{- $autoHTTPS := (and $HTTPS (eq .Values.apps.jupyterhub.proxy.https.type "letsencrypt")) }} -{{- if $autoHTTPS -}} -apiVersion: v1 -kind: Service -metadata: - name: {{ include "jupyterhub.proxy-http.fullname" . }} - labels: - {{- include "jupyterhub.labels" . | nindent 4 }} - {{- with .Values.apps.jupyterhub.proxy.service.labels }} - {{- . | toYaml | nindent 4 }} - {{- end }} - {{- with .Values.apps.jupyterhub.proxy.service.annotations }} - annotations: - {{- . | toYaml | nindent 4 }} - {{- end }} -spec: - type: ClusterIP - selector: - {{- $_ := merge (dict "componentLabel" "proxy") . }} - {{- include "jupyterhub.matchLabels" $_ | nindent 4 }} - ports: - - port: 8000 - targetPort: http -{{- end }} diff --git a/applications/jupyterhub/deploy/templates/proxy/deployment.yaml b/applications/jupyterhub/deploy/templates/proxy/deployment.yaml index 6d63ba880..bb37b8f03 100755 --- a/applications/jupyterhub/deploy/templates/proxy/deployment.yaml +++ b/applications/jupyterhub/deploy/templates/proxy/deployment.yaml @@ -7,6 +7,9 @@ metadata: labels: {{- include "jupyterhub.labels" . | nindent 4 }} spec: + {{- if typeIs "int" .Values.apps.jupyterhub.proxy.chp.revisionHistoryLimit }} + revisionHistoryLimit: {{ .Values.apps.jupyterhub.proxy.chp.revisionHistoryLimit }} + {{- end }} replicas: 1 selector: matchLabels: @@ -35,7 +38,7 @@ spec: # match the k8s Secret during the first upgrade following an auth_token # was generated. checksum/auth-token: {{ include "jupyterhub.hub.config.ConfigurableHTTPProxy.auth_token" . | sha256sum | trunc 4 | quote }} - checksum/proxy-secret: {{ include (print $.Template.BasePath "/jupyterhub/hub/secret.yaml") . | sha256sum }} + checksum/proxy-secret: {{ include (print $.Template.BasePath "/jupyterhub/proxy/secret.yaml") . | sha256sum | quote }} {{- with .Values.apps.jupyterhub.proxy.annotations }} {{- . | toYaml | nindent 8 }} {{- end }} @@ -44,7 +47,10 @@ spec: {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} priorityClassName: {{ include "jupyterhub.priority.fullname" . }} {{- end }} - nodeSelector: {{ toJson .Values.apps.jupyterhub.proxy.chp.nodeSelector }} + {{- with .Values.apps.jupyterhub.proxy.chp.nodeSelector }} + nodeSelector: + {{- . | toYaml | nindent 8 }} + {{- end }} {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.proxy.chp.tolerations }} tolerations: {{- . | toYaml | nindent 8 }} @@ -135,6 +141,8 @@ spec: livenessProbe: initialDelaySeconds: {{ .Values.apps.jupyterhub.proxy.chp.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.apps.jupyterhub.proxy.chp.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.apps.jupyterhub.proxy.chp.livenessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.apps.jupyterhub.proxy.chp.livenessProbe.failureThreshold }} httpGet: path: /_chp_healthz {{- if or $manualHTTPS $manualHTTPSwithsecret }} @@ -149,6 +157,8 @@ spec: readinessProbe: initialDelaySeconds: {{ .Values.apps.jupyterhub.proxy.chp.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.apps.jupyterhub.proxy.chp.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.apps.jupyterhub.proxy.chp.readinessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.apps.jupyterhub.proxy.chp.readinessProbe.failureThreshold }} httpGet: path: /_chp_healthz {{- if or $manualHTTPS $manualHTTPSwithsecret }} diff --git a/applications/jupyterhub/deploy/templates/proxy/netpol.yaml b/applications/jupyterhub/deploy/templates/proxy/netpol.yaml index adc827731..88a00be6a 100755 --- a/applications/jupyterhub/deploy/templates/proxy/netpol.yaml +++ b/applications/jupyterhub/deploy/templates/proxy/netpol.yaml @@ -85,32 +85,24 @@ spec: egress: # proxy --> hub - - ports: - - port: 8081 - to: + - to: - podSelector: matchLabels: {{- $_ := merge (dict "componentLabel" "hub") . }} {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} + ports: + - port: 8081 # proxy --> singleuser-server - - ports: - - port: 8888 - to: + - to: - podSelector: matchLabels: {{- $_ := merge (dict "componentLabel" "singleuser-server") . }} {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} + ports: + - port: 8888 - # proxy --> Kubernetes internal DNS - - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - {{- with .Values.apps.jupyterhub.proxy.chp.networkPolicy.egress }} - # proxy --> depends, but the default is everything - {{- . | toYaml | nindent 4 }} + {{- with (include "jupyterhub.networkPolicy.renderEgressRules" (list . .Values.apps.jupyterhub.proxy.chp.networkPolicy)) }} + {{- . | nindent 4 }} {{- end }} {{- end }} diff --git a/applications/jupyterhub/deploy/templates/proxy/pdb.yaml b/applications/jupyterhub/deploy/templates/proxy/pdb.yaml index 1846a3b00..155895b06 100755 --- a/applications/jupyterhub/deploy/templates/proxy/pdb.yaml +++ b/applications/jupyterhub/deploy/templates/proxy/pdb.yaml @@ -1,9 +1,5 @@ {{- if .Values.apps.jupyterhub.proxy.chp.pdb.enabled -}} -{{- if .Capabilities.APIVersions.Has "policy/v1" }} apiVersion: policy/v1 -{{- else }} -apiVersion: policy/v1beta1 -{{- end }} kind: PodDisruptionBudget metadata: name: {{ include "jupyterhub.proxy.fullname" . }} diff --git a/applications/jupyterhub/deploy/templates/proxy/service.yaml b/applications/jupyterhub/deploy/templates/proxy/service.yaml index 0d9ca5b2c..f634ba9e5 100755 --- a/applications/jupyterhub/deploy/templates/proxy/service.yaml +++ b/applications/jupyterhub/deploy/templates/proxy/service.yaml @@ -35,12 +35,15 @@ metadata: {{- end }} spec: selector: + # This service will target the autohttps pod if autohttps is configured, and + # the proxy pod if not. When autohttps is configured, the service proxy-http + # will be around to target the proxy pod directly. {{- if $autoHTTPS }} - component: autohttps + {{- $_ := merge (dict "componentLabel" "autohttps") . -}} + {{- include "jupyterhub.matchLabels" $_ | nindent 4 }} {{- else }} - component: proxy + {{- include "jupyterhub.matchLabels" . | nindent 4 }} {{- end }} - release: {{ .Release.Name }} ports: {{- if $HTTPS }} - name: https diff --git a/applications/jupyterhub/deploy/templates/scheduling/priorityclass.yaml b/applications/jupyterhub/deploy/templates/scheduling/priorityclass.yaml index 588cf196c..1bed905e1 100755 --- a/applications/jupyterhub/deploy/templates/scheduling/priorityclass.yaml +++ b/applications/jupyterhub/deploy/templates/scheduling/priorityclass.yaml @@ -4,22 +4,9 @@ kind: PriorityClass metadata: name: {{ include "jupyterhub.priority.fullname" . }} annotations: - # FIXME: PriorityClasses must be added before the other resources reference - # them, and in the past a workaround was needed to accomplish this: - # to make the resource a Helm hook. - # - # To transition this resource to no longer be a Helm hook resource, - # we explicitly add ownership annotations/labels (in 1.0.0) which - # will allow a future upgrade (in 2.0.0) to remove all hook and - # ownership annotations/labels. - # - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-delete-policy: before-hook-creation - helm.sh/hook-weight: "-100" meta.helm.sh/release-name: "{{ .Release.Name }}" meta.helm.sh/release-namespace: "{{ .Release.Namespace }}" labels: - app.kubernetes.io/managed-by: Helm {{- $_ := merge (dict "componentLabel" "default-priority") . }} {{- include "jupyterhub.labels" $_ | nindent 4 }} value: {{ .Values.apps.jupyterhub.scheduling.podPriority.defaultPriority }} diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/pdb.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/pdb.yaml index b1dc6c5d0..800ac2086 100755 --- a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/pdb.yaml +++ b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/pdb.yaml @@ -3,11 +3,7 @@ The cluster autoscaler should be allowed to evict and reschedule these pods if it would help in order to scale down a node. */}} {{- if .Values.apps.jupyterhub.scheduling.userPlaceholder.enabled -}} -{{- if .Capabilities.APIVersions.Has "policy/v1" }} apiVersion: policy/v1 -{{- else }} -apiVersion: policy/v1beta1 -{{- end }} kind: PodDisruptionBudget metadata: name: {{ include "jupyterhub.user-placeholder.fullname" . }} diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/priorityclass.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/priorityclass.yaml index e03497dba..688e217cd 100755 --- a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/priorityclass.yaml +++ b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/priorityclass.yaml @@ -5,22 +5,9 @@ kind: PriorityClass metadata: name: {{ include "jupyterhub.user-placeholder-priority.fullname" . }} annotations: - # FIXME: PriorityClasses must be added before the other resources reference - # them, and in the past a workaround was needed to accomplish this: - # to make the resource a Helm hook. - # - # To transition this resource to no longer be a Helm hook resource, - # we explicitly add ownership annotations/labels (in 1.0.0) which - # will allow a future upgrade (in 2.0.0) to remove all hook and - # ownership annotations/labels. - # - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-delete-policy: before-hook-creation - helm.sh/hook-weight: "-100" meta.helm.sh/release-name: "{{ .Release.Name }}" meta.helm.sh/release-namespace: "{{ .Release.Namespace }}" labels: - app.kubernetes.io/managed-by: Helm {{- include "jupyterhub.labels" . | nindent 4 }} value: {{ .Values.apps.jupyterhub.scheduling.podPriority.userPlaceholderPriority }} globalDefault: false diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/statefulset.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/statefulset.yaml index 114f62629..c243beee3 100755 --- a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/statefulset.yaml +++ b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/statefulset.yaml @@ -16,6 +16,9 @@ metadata: {{- include "jupyterhub.labels" . | nindent 4 }} spec: podManagementPolicy: Parallel + {{- if typeIs "int" .Values.apps.jupyterhub.scheduling.userPlaceholder.revisionHistoryLimit }} + revisionHistoryLimit: {{ .Values.apps.jupyterhub.scheduling.userPlaceholder.revisionHistoryLimit }} + {{- end }} replicas: {{ .Values.apps.jupyterhub.scheduling.userPlaceholder.replicas }} selector: matchLabels: @@ -23,9 +26,16 @@ spec: serviceName: {{ include "jupyterhub.user-placeholder.fullname" . }} template: metadata: + {{- with .Values.apps.jupyterhub.scheduling.userPlaceholder.annotations }} + annotations: + {{- . | toYaml | nindent 8 }} + {{- end }} labels: {{- /* Changes here will cause the Deployment to restart the pods. */}} {{- include "jupyterhub.matchLabels" . | nindent 8 }} + {{- with .Values.apps.jupyterhub.scheduling.userPlaceholder.labels }} + {{- . | toYaml | nindent 8 }} + {{- end }} spec: {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} priorityClassName: {{ include "jupyterhub.user-placeholder-priority.fullname" . }} @@ -33,7 +43,10 @@ spec: {{- if .Values.apps.jupyterhub.scheduling.userScheduler.enabled }} schedulerName: {{ include "jupyterhub.user-scheduler.fullname" . }} {{- end }} - nodeSelector: {{ toJson .Values.apps.jupyterhub.singleuser.nodeSelector }} + {{- with .Values.apps.jupyterhub.singleuser.nodeSelector }} + nodeSelector: + {{- . | toYaml | nindent 8 }} + {{- end }} {{- with concat .Values.apps.jupyterhub.scheduling.userPods.tolerations .Values.apps.jupyterhub.singleuser.extraTolerations }} tolerations: {{- . | toYaml | nindent 8 }} diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/configmap.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/configmap.yaml index ef8a37f67..3e83b444f 100755 --- a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/configmap.yaml +++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/configmap.yaml @@ -6,16 +6,28 @@ metadata: labels: {{- include "jupyterhub.labels" . | nindent 4 }} data: - # ref: https://kubernetes.io/docs/reference/scheduling/config/ + {{- /* + This is configuration of a k8s official kube-scheduler binary running in the + user-scheduler. + + ref: https://kubernetes.io/docs/reference/scheduling/config/ + ref: https://kubernetes.io/docs/reference/config-api/kube-scheduler-config.v1/ + */}} config.yaml: | - apiVersion: kubescheduler.config.k8s.io/v1beta1 + apiVersion: kubescheduler.config.k8s.io/v1 kind: KubeSchedulerConfiguration leaderElection: - resourceLock: endpoints + resourceLock: leases resourceName: {{ include "jupyterhub.user-scheduler-lock.fullname" . }} resourceNamespace: "{{ .Release.Namespace }}" profiles: - schedulerName: {{ include "jupyterhub.user-scheduler.fullname" . }} + {{- with .Values.apps.jupyterhub.scheduling.userScheduler.plugins }} plugins: - {{- .Values.apps.jupyterhub.scheduling.userScheduler.plugins | toYaml | nindent 10 }} + {{- . | toYaml | nindent 10 }} + {{- end }} + {{- with .Values.apps.jupyterhub.scheduling.userScheduler.pluginConfig }} + pluginConfig: + {{- . | toYaml | nindent 10 }} + {{- end }} {{- end }} diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/deployment.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/deployment.yaml index 1bcaf317c..f22d0de89 100755 --- a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/deployment.yaml +++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/deployment.yaml @@ -6,6 +6,9 @@ metadata: labels: {{- include "jupyterhub.labels" . | nindent 4 }} spec: + {{- if typeIs "int" .Values.apps.jupyterhub.scheduling.userScheduler.revisionHistoryLimit }} + revisionHistoryLimit: {{ .Values.apps.jupyterhub.scheduling.userScheduler.revisionHistoryLimit }} + {{- end }} replicas: {{ .Values.apps.jupyterhub.scheduling.userScheduler.replicas }} selector: matchLabels: @@ -14,16 +17,25 @@ spec: metadata: labels: {{- include "jupyterhub.matchLabels" . | nindent 8 }} + {{- with .Values.apps.jupyterhub.scheduling.userScheduler.labels }} + {{- . | toYaml | nindent 8 }} + {{- end }} annotations: checksum/config-map: {{ include (print $.Template.BasePath "/jupyterhub/scheduling/user-scheduler/configmap.yaml") . | sha256sum }} + {{- with .Values.apps.jupyterhub.scheduling.userScheduler.annotations }} + {{- . | toYaml | nindent 8 }} + {{- end }} spec: - {{- if .Values.apps.jupyterhub.rbac.enabled }} - serviceAccountName: {{ include "jupyterhub.user-scheduler-deploy.fullname" . }} + {{ with include "jupyterhub.user-scheduler-serviceaccount.fullname" . }} + serviceAccountName: {{ . }} {{- end }} {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} priorityClassName: {{ include "jupyterhub.priority.fullname" . }} {{- end }} - nodeSelector: {{ toJson .Values.apps.jupyterhub.scheduling.userScheduler.nodeSelector }} + {{- with .Values.apps.jupyterhub.scheduling.userScheduler.nodeSelector }} + nodeSelector: + {{- . | toYaml | nindent 8 }} + {{- end }} {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.scheduling.userScheduler.tolerations }} tolerations: {{- . | toYaml | nindent 8 }} @@ -44,13 +56,6 @@ spec: {{- end }} command: - /usr/local/bin/kube-scheduler - # NOTE: --leader-elect-... (new) and --lock-object-... (deprecated) - # flags are silently ignored in favor of whats defined in the - # passed KubeSchedulerConfiguration whenever --config is - # passed. - # - # ref: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/ - # # NOTE: --authentication-skip-lookup=true is used to avoid a # seemingly harmless error, if we need to not skip # "authentication lookup" in the future, see the linked issue. @@ -65,12 +70,14 @@ spec: livenessProbe: httpGet: path: /healthz - port: 10251 + scheme: HTTPS + port: 10259 initialDelaySeconds: 15 readinessProbe: httpGet: path: /healthz - port: 10251 + scheme: HTTPS + port: 10259 {{- with .Values.apps.jupyterhub.scheduling.userScheduler.resources }} resources: {{- . | toYaml | nindent 12 }} diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/pdb.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/pdb.yaml index 04f2af8c3..2c9c6de81 100755 --- a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/pdb.yaml +++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/pdb.yaml @@ -1,9 +1,5 @@ {{- if and .Values.apps.jupyterhub.scheduling.userScheduler.enabled .Values.apps.jupyterhub.scheduling.userScheduler.pdb.enabled -}} -{{- if .Capabilities.APIVersions.Has "policy/v1" }} apiVersion: policy/v1 -{{- else }} -apiVersion: policy/v1beta1 -{{- end }} kind: PodDisruptionBudget metadata: name: {{ include "jupyterhub.user-scheduler-deploy.fullname" . }} diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/rbac.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/rbac.yaml index 083e06542..9c7fab736 100755 --- a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/rbac.yaml +++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/rbac.yaml @@ -1,16 +1,5 @@ {{- if .Values.apps.jupyterhub.scheduling.userScheduler.enabled -}} -{{- if .Values.apps.jupyterhub.rbac.enabled }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "jupyterhub.user-scheduler-deploy.fullname" . }} - labels: - {{- include "jupyterhub.labels" . | nindent 4 }} - {{- with .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.annotations }} - annotations: - {{- . | toYaml | nindent 4 }} - {{- end }} ---- +{{- if .Values.apps.jupyterhub.rbac.create -}} kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -19,13 +8,23 @@ metadata: {{- include "jupyterhub.labels" . | nindent 4 }} rules: # Copied from the system:kube-scheduler ClusterRole of the k8s version - # matching the kube-scheduler binary we use. A modification of two resource - # name references from kube-scheduler to user-scheduler-lock was made. + # matching the kube-scheduler binary we use. A modification has been made to + # resourceName fields to remain relevant for how we have named our resources + # in this Helm chart. # - # NOTE: These rules have been unchanged between 1.12 and 1.15, then changed in - # 1.16 and in 1.17, but unchanged in 1.18 and 1.19. + # NOTE: These rules have been: + # - unchanged between 1.12 and 1.15 + # - changed in 1.16 + # - changed in 1.17 + # - unchanged between 1.18 and 1.20 + # - changed in 1.21: get/list/watch permission for namespace, + # csidrivers, csistoragecapacities was added. + # - unchanged between 1.22 and 1.27 + # - changed in 1.28: permissions to get/update lock endpoint resource + # removed + # - unchanged between 1.28 and 1.29 # - # ref: https://github.com/kubernetes/kubernetes/blob/v1.19.0/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml#L696-L829 + # ref: https://github.com/kubernetes/kubernetes/blob/v1.29.0/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml#L721-L862 - apiGroups: - "" - events.k8s.io @@ -50,21 +49,6 @@ rules: verbs: - get - update - - apiGroups: - - "" - resources: - - endpoints - verbs: - - create - - apiGroups: - - "" - resourceNames: - - {{ include "jupyterhub.user-scheduler-lock.fullname" . }} - resources: - - endpoints - verbs: - - get - - update - apiGroups: - "" resources: @@ -159,13 +143,37 @@ rules: - get - list - watch + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch + - apiGroups: + - storage.k8s.io + resources: + - csidrivers + verbs: + - get + - list + - watch + - apiGroups: + - storage.k8s.io + resources: + - csistoragecapacities + verbs: + - get + - list + - watch # Copied from the system:volume-scheduler ClusterRole of the k8s version # matching the kube-scheduler binary we use. # - # NOTE: These rules have not changed between 1.12 and 1.19. + # NOTE: These rules have not changed between 1.12 and 1.29. # - # ref: https://github.com/kubernetes/kubernetes/blob/v1.19.0/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml#L1213-L1240 + # ref: https://github.com/kubernetes/kubernetes/blob/v1.29.0/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml#L1283-L1310 - apiGroups: - "" resources: @@ -203,7 +211,7 @@ metadata: {{- include "jupyterhub.labels" . | nindent 4 }} subjects: - kind: ServiceAccount - name: {{ include "jupyterhub.user-scheduler-deploy.fullname" . }} + name: {{ include "jupyterhub.user-scheduler-serviceaccount.fullname" . }} namespace: "{{ .Release.Namespace }}" roleRef: kind: ClusterRole diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/serviceaccount.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/serviceaccount.yaml new file mode 100644 index 000000000..67618b036 --- /dev/null +++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/serviceaccount.yaml @@ -0,0 +1,14 @@ +{{- if .Values.apps.jupyterhub.scheduling.userScheduler.enabled -}} +{{- if .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "jupyterhub.user-scheduler-serviceaccount.fullname" . }} + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} + {{- with .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.annotations }} + annotations: + {{- . | toYaml | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/applications/jupyterhub/deploy/templates/singleuser/netpol.yaml b/applications/jupyterhub/deploy/templates/singleuser/netpol.yaml index 3dfb1378d..931a150fe 100755 --- a/applications/jupyterhub/deploy/templates/singleuser/netpol.yaml +++ b/applications/jupyterhub/deploy/templates/singleuser/netpol.yaml @@ -62,23 +62,38 @@ spec: egress: # singleuser-server --> hub - - ports: - - port: 8081 - to: + - to: - podSelector: matchLabels: {{- $_ := merge (dict "componentLabel" "hub") . }} {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} + ports: + - port: 8081 - # singleuser-server --> Kubernetes internal DNS - - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 + # singleuser-server --> proxy + # singleuser-server --> autohttps + # + # While not critical for core functionality, a user or library code may rely + # on communicating with the proxy or autohttps pods via a k8s Service it can + # detected from well known environment variables. + # + - to: + - podSelector: + matchLabels: + {{- $_ := merge (dict "componentLabel" "proxy") . }} + {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} + ports: + - port: 8000 + - to: + - podSelector: + matchLabels: + {{- $_ := merge (dict "componentLabel" "autohttps") . }} + {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} + ports: + - port: 8080 + - port: 8443 - {{- with .Values.apps.jupyterhub.singleuser.networkPolicy.egress }} - # singleuser-server --> depends, but the default is everything - {{- . | toYaml | nindent 4 }} + {{- with (include "jupyterhub.networkPolicy.renderEgressRules" (list . .Values.apps.jupyterhub.singleuser.networkPolicy)) }} + {{- . | nindent 4 }} {{- end }} {{- end }} diff --git a/applications/jupyterhub/deploy/templates/singleuser/secret.yaml b/applications/jupyterhub/deploy/templates/singleuser/secret.yaml new file mode 100644 index 000000000..e6eab9bd0 --- /dev/null +++ b/applications/jupyterhub/deploy/templates/singleuser/secret.yaml @@ -0,0 +1,17 @@ +{{- if .Values.apps.jupyterhub.singleuser.extraFiles }} +kind: Secret +apiVersion: v1 +metadata: + name: {{ include "jupyterhub.singleuser.fullname" . }} + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} +type: Opaque +{{- with include "jupyterhub.extraFiles.data" .Values.apps.jupyterhub.singleuser.extraFiles }} +data: + {{- . | nindent 2 }} +{{- end }} +{{- with include "jupyterhub.extraFiles.stringData" .Values.apps.jupyterhub.singleuser.extraFiles }} +stringData: + {{- . | nindent 2 }} +{{- end }} +{{- end }} diff --git a/applications/jupyterhub/deploy/values.schema.yaml b/applications/jupyterhub/deploy/values.schema.yaml new file mode 100644 index 000000000..69c13a83c --- /dev/null +++ b/applications/jupyterhub/deploy/values.schema.yaml @@ -0,0 +1,3014 @@ +# This schema (a jsonschema in YAML format) is used to generate +# values.schema.json which is packaged with the Helm chart for client side +# validation by helm of values before template rendering. +# +# This schema is also used by our documentation system to build the +# configuration reference section based on the description fields. See +# docs/source/conf.py for that logic! +# +# We look to document everything we have default values for in values.yaml, but +# we don't look to enforce the perfect validation logic within this file. +# +# ref: https://json-schema.org/learn/getting-started-step-by-step.html +# +$schema: http://json-schema.org/draft-07/schema# +type: object +additionalProperties: false +required: + - imagePullSecrets + - hub + - proxy + - singleuser + - ingress + - prePuller + - custom + - cull + - debug + - rbac + - global +properties: + enabled: + type: [boolean, "null"] + description: | + `enabled` is ignored by the jupyterhub chart itself, but a chart depending + on the jupyterhub chart conditionally can make use this config option as + the condition. + fullnameOverride: + type: [string, "null"] + description: | + fullnameOverride and nameOverride allow you to adjust how the resources + part of the Helm chart are named. + + Name format | Resource types | fullnameOverride | nameOverride | Note + ------------------------- | -------------- | ---------------- | ------------ | - + component | namespaced | `""` | * | Default + release-component | cluster wide | `""` | * | Default + fullname-component | * | str | * | - + release-component | * | null | `""` | - + release-(name-)component | * | null | str | omitted if contained in release + release-(chart-)component | * | null | null | omitted if contained in release + + ```{admonition} Warning! + :class: warning + Changing fullnameOverride or nameOverride after the initial installation + of the chart isn't supported. Changing their values likely leads to a + reset of non-external JupyterHub databases, abandonment of users' storage, + and severed couplings to currently running user pods. + ``` + + If you are a developer of a chart depending on this chart, you should + avoid hardcoding names. If you want to reference the name of a resource in + this chart from a parent helm chart's template, you can make use of the + global named templates instead. + + ```yaml + # some pod definition of a parent chart helm template + schedulerName: {{ include "jupyterhub.user-scheduler.fullname" . }} + ``` + + To access them from a container, you can also rely on the hub ConfigMap + that contains entries of all the resource names. + + ```yaml + # some container definition in a parent chart helm template + env: + - name: SCHEDULER_NAME + valueFrom: + configMapKeyRef: + name: {{ include "jupyterhub.user-scheduler.fullname" . }} + key: user-scheduler + ``` + + nameOverride: + type: [string, "null"] + description: | + See the documentation under [`fullnameOverride`](schema_fullnameOverride). + + imagePullSecret: + type: object + required: [create] + if: + properties: + create: + const: true + then: + additionalProperties: false + required: [registry, username, password] + description: | + This is configuration to create a k8s Secret resource of `type: + kubernetes.io/dockerconfigjson`, with credentials to pull images from a + private image registry. If you opt to do so, it will be available for use + by all pods in their respective `spec.imagePullSecrets` alongside other + k8s Secrets defined in `imagePullSecrets` or the pod respective + `...image.pullSecrets` configuration. + + In other words, using this configuration option can automate both the + otherwise manual creation of a k8s Secret and the otherwise manual + configuration to reference this k8s Secret in all the pods of the Helm + chart. + + ```sh + # you won't need to create a k8s Secret manually... + kubectl create secret docker-registry image-pull-secret \ + --docker-server= \ + --docker-username= \ + --docker-email= \ + --docker-password= + ``` + + If you just want to let all Pods reference an existing secret, use the + [`imagePullSecrets`](schema_imagePullSecrets) configuration instead. + properties: + create: + type: boolean + description: | + Toggle the creation of the k8s Secret with provided credentials to + access a private image registry. + automaticReferenceInjection: + type: boolean + description: | + Toggle the automatic reference injection of the created Secret to all + pods' `spec.imagePullSecrets` configuration. + registry: + type: string + description: | + Name of the private registry you want to create a credential set for. + It will default to Docker Hub's image registry. + + Examples: + - https://index.docker.io/v1/ + - quay.io + - eu.gcr.io + - alexmorreale.privatereg.net + username: + type: string + description: | + Name of the user you want to use to connect to your private registry. + + For external gcr.io, you will use the `_json_key`. + + Examples: + - alexmorreale + - alex@pfc.com + - _json_key + password: + type: string + description: | + Password for the private image registry's user. + + Examples: + - plaintextpassword + - abc123SECRETzyx098 + + For gcr.io registries the password will be a big JSON blob for a + Google cloud service account, it should look something like below. + + ```yaml + password: |- + { + "type": "service_account", + "project_id": "jupyter-se", + "private_key_id": "f2ba09118a8d3123b3321bd9a7d6d0d9dc6fdb85", + ... + } + ``` + email: + type: [string, "null"] + description: | + Specification of an email is most often not required, but it is + supported. + + imagePullSecrets: + type: array + description: | + Chart wide configuration to _append_ k8s Secret references to all its + pod's `spec.imagePullSecrets` configuration. + + This will not override or get overridden by pod specific configuration, + but instead augment the pod specific configuration. + + You can use both the k8s native syntax, where each list element is like + `{"name": "my-secret-name"}`, or you can let list elements be strings + naming the secrets directly. + + hub: + type: object + additionalProperties: false + required: [baseUrl] + properties: + revisionHistoryLimit: &revisionHistoryLimit + type: [integer, "null"] + minimum: 0 + description: | + Configures the resource's `spec.revisionHistoryLimit`. This is + available for Deployment, StatefulSet, and DaemonSet resources. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#revision-history-limit) + for more info. + config: + type: object + additionalProperties: true + description: | + JupyterHub and its components (authenticators, spawners, etc), are + Python classes that expose its configuration through + [_traitlets_](https://traitlets.readthedocs.io/en/stable/). With this + Helm chart configuration (`hub.config`), you can directly configure + the Python classes through _static_ YAML values. To _dynamically_ set + values, you need to use [`hub.extraConfig`](schema_hub.extraConfig) + instead. + + ```{admonition} Currently intended only for auth config + :class: warning + This config _currently_ (0.11.0) only influence the software in the + `hub` Pod, but some Helm chart config options such as + [`hub.baseUrl`](schema_hub.baseUrl) is used to set + `JupyterHub.base_url` in the `hub` Pod _and_ influence how other Helm + templates are rendered. + + As we have not yet mapped out all the potential configuration + conflicts except for the authentication related configuration options, + please accept that using it for something else at this point can lead + to issues. + ``` + + __Example__ + + If you inspect documentation or some `jupyterhub_config.py` to contain + the following section: + + ```python + c.JupyterHub.admin_access = true + c.JupyterHub.admin_users = ["jovyan1", "jovyan2"] + c.KubeSpawner.k8s_api_request_timeout = 10 + c.GitHubOAuthenticator.allowed_organizations = ["jupyterhub"] + ``` + + Then, you would be able to represent it with this configuration like: + + ```yaml + hub: + config: + JupyterHub: + admin_access: true + admin_users: + - jovyan1 + - jovyan2 + KubeSpawner: + k8s_api_request_timeout: 10 + GitHubOAuthenticator: + allowed_organizations: + - jupyterhub + ``` + + ```{admonition} YAML limitations + :class: tip + You can't represent Python `Bytes` or `Set` objects in YAML directly. + ``` + + ```{admonition} Helm value merging + :class: tip + `helm` merges a Helm chart's default values with values passed with + the `--values` or `-f` flag. During merging, lists are replaced while + dictionaries are updated. + ``` + extraFiles: &extraFiles + type: object + additionalProperties: false + description: | + A dictionary with extra files to be injected into the pod's container + on startup. This can for example be used to inject: configuration + files, custom user interface templates, images, and more. + + ```yaml + # NOTE: "hub" is used in this example, but the configuration is the + # same for "singleuser". + hub: + extraFiles: + # The file key is just a reference that doesn't influence the + # actual file name. + : + # mountPath is required and must be the absolute file path. + mountPath: + + # Choose one out of the three ways to represent the actual file + # content: data, stringData, or binaryData. + # + # data should be set to a mapping (dictionary). It will in the + # end be rendered to either YAML, JSON, or TOML based on the + # filename extension that are required to be either .yaml, .yml, + # .json, or .toml. + # + # If your content is YAML, JSON, or TOML, it can make sense to + # use data to represent it over stringData as data can be merged + # instead of replaced if set partially from separate Helm + # configuration files. + # + # Both stringData and binaryData should be set to a string + # representing the content, where binaryData should be the + # base64 encoding of the actual file content. + # + data: + myConfig: + myMap: + number: 123 + string: "hi" + myList: + - 1 + - 2 + stringData: | + hello world! + binaryData: aGVsbG8gd29ybGQhCg== + + # mode is by default 0644 and you can optionally override it + # either by octal notation (example: 0400) or decimal notation + # (example: 256). + mode: + ``` + + **Using --set-file** + + To avoid embedding entire files in the Helm chart configuration, you + can use the `--set-file` flag during `helm upgrade` to set the + stringData or binaryData field. + + ```yaml + hub: + extraFiles: + my_image: + mountPath: /usr/local/share/jupyterhub/static/my_image.png + + # Files in /usr/local/etc/jupyterhub/jupyterhub_config.d are + # automatically loaded in alphabetical order of the final file + # name when JupyterHub starts. + my_config: + mountPath: /usr/local/etc/jupyterhub/jupyterhub_config.d/my_jupyterhub_config.py + ``` + + ```bash + # --set-file expects a text based file, so you need to base64 encode + # it manually first. + base64 my_image.png > my_image.png.b64 + + helm upgrade <...> \ + --set-file hub.extraFiles.my_image.binaryData=./my_image.png.b64 \ + --set-file hub.extraFiles.my_config.stringData=./my_jupyterhub_config.py + ``` + + **Common uses** + + 1. **JupyterHub template customization** + + You can replace the default JupyterHub user interface templates in + the hub pod by injecting new ones to + `/usr/local/share/jupyterhub/templates`. These can in turn + reference custom images injected to + `/usr/local/share/jupyterhub/static`. + + 1. **JupyterHub standalone file config** + + Instead of embedding JupyterHub python configuration as a string + within a YAML file through + [`hub.extraConfig`](schema_hub.extraConfig), you can inject a + standalone .py file into + `/usr/local/etc/jupyterhub/jupyterhub_config.d` that is + automatically loaded. + + 1. **Flexible configuration** + + By injecting files, you don't have to embed them in a docker image + that you have to rebuild. + + If your configuration file is a YAML/JSON/TOML file, you can also + use `data` instead of `stringData` which allow you to set various + configuration in separate Helm config files. This can be useful to + help dependent charts override only some configuration part of the + file, or to allow for the configuration be set through multiple + Helm configuration files. + + **Limitations** + + 1. File size + + The files in `hub.extraFiles` and `singleuser.extraFiles` are + respectively stored in their own k8s Secret resource. As k8s + Secret's are limited, typically to 1MB, you will be limited to a + total file size of less than 1MB as there is also base64 encoding + that takes place reducing available capacity to 75%. + + 2. File updates + + The files that are mounted are only set during container startup. + This is [because we use + `subPath`](https://kubernetes.io/docs/concepts/storage/volumes/#secret) + as is required to avoid replacing the content of the entire + directory we mount in. + patternProperties: + ".*": + type: object + additionalProperties: false + required: [mountPath] + oneOf: + - required: [data] + - required: [stringData] + - required: [binaryData] + properties: + mountPath: + type: string + data: + type: object + additionalProperties: true + stringData: + type: string + binaryData: + type: string + mode: + type: number + baseUrl: + type: string + description: | + This is the equivalent of c.JupyterHub.base_url, but it is also needed + by the Helm chart in general. So, instead of setting + c.JupyterHub.base_url, use this configuration. + command: + type: array + description: | + A list of strings to be used to replace the JupyterHub image's + `ENTRYPOINT` entry. Note that in k8s lingo, the Dockerfile's + `ENTRYPOINT` is called `command`. The list of strings will be expanded + with Helm's template function `tpl` which can render Helm template + logic inside curly braces (`{{... }}`). + + This could be useful to wrap the invocation of JupyterHub itself in + some custom way. + + For more details, see the [Kubernetes + documentation](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/). + args: + type: array + description: | + A list of strings to be used to replace the JupyterHub image's `CMD` + entry as well as the Helm chart's default way to start JupyterHub. + Note that in k8s lingo, the Dockerfile's `CMD` is called `args`. The + list of strings will be expanded with Helm's template function `tpl` + which can render Helm template logic inside curly braces (`{{... }}`). + + ```{warning} + By replacing the entire configuration file, which is mounted to + `/usr/local/etc/jupyterhub/jupyterhub_config.py` by the Helm chart, + instead of appending to it with `hub.extraConfig`, you expose your + deployment for issues stemming from getting out of sync with the Helm + chart's config file. + + These kind of issues will be significantly harder to debug and + diagnose, and can due to this could cause a lot of time expenditure + for both the community maintaining the Helm chart as well as yourself, + even if this wasn't the reason for the issue. + + Due to this, we ask that you do your _absolute best to avoid replacing + the default provided `jupyterhub_config.py` file. It can often be + possible. For example, if your goal is to have a dedicated .py file + for more extensive additions that you can syntax highlight and such + and feel limited by passing code in `hub.extraConfig` which is part of + a YAML file, you can use [this + trick](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/issues/1580#issuecomment-707776237) + instead. + ``` + + ```yaml + hub: + args: + - "jupyterhub" + - "--config" + - "/usr/local/etc/jupyterhub/jupyterhub_config.py" + - "--debug" + - "--upgrade-db" + ``` + + For more details, see the [Kubernetes + documentation](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/). + cookieSecret: + type: [string, "null"] + description: | + ```{note} + As of version 1.0.0 this will automatically be generated and there is + no need to set it manually. + + If you wish to reset a generated key, you can use `kubectl edit` on + the k8s Secret typically named `hub` and remove the + `hub.config.JupyterHub.cookie_secret` entry in the k8s Secret, then + perform a new `helm upgrade`. + ``` + + A 32-byte cryptographically secure randomly generated string used to sign values of + secure cookies set by the hub. If unset, jupyterhub will generate one on startup and + save it in the file `jupyterhub_cookie_secret` in the `/srv/jupyterhub` directory of + the hub container. A value set here will make JupyterHub overwrite any previous file. + + You do not need to set this at all if you are using the default configuration for + storing databases - sqlite on a persistent volume (with `hub.db.type` set to the + default `sqlite-pvc`). If you are using an external database, then you must set this + value explicitly - or your users will keep getting logged out each time the hub pod + restarts. + + Changing this value will all user logins to be invalidated. If this secret leaks, + *immediately* change it to something else, or user data can be compromised + + ```sh + # to generate a value, run + openssl rand -hex 32 + ``` + image: &image-spec + type: object + additionalProperties: false + required: [name, tag] + description: | + Set custom image name, tag, pullPolicy, or pullSecrets for the pod. + properties: + name: + type: string + description: | + The name of the image, without the tag. + + ``` + # example name + gcr.io/my-project/my-image + ``` + tag: + type: string + description: | + The tag of the image to pull. This is the value following `:` in + complete image specifications. + + ``` + # example tags + v1.11.1 + zhy270a + ``` + pullPolicy: + enum: [null, "", IfNotPresent, Always, Never] + description: | + Configures the Pod's `spec.imagePullPolicy`. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/containers/images/#updating-images) + for more info. + pullSecrets: + type: array + description: | + A list of references to existing Kubernetes Secrets with + credentials to pull the image. + + This Pod's final `imagePullSecrets` k8s specification will be a + combination of: + + 1. This list of k8s Secrets, specific for this pod. + 2. The list of k8s Secrets, for use by all pods in the Helm chart, + declared in this Helm charts configuration called + `imagePullSecrets`. + 3. A k8s Secret, for use by all pods in the Helm chart, if + conditionally created from image registry credentials provided + under `imagePullSecret` if `imagePullSecret.create` is set to + true. + + ```yaml + # example - k8s native syntax + pullSecrets: + - name: my-k8s-secret-with-image-registry-credentials + + # example - simplified syntax + pullSecrets: + - my-k8s-secret-with-image-registry-credentials + ``` + networkPolicy: &networkPolicy-spec + type: object + additionalProperties: false + description: | + This configuration regards the creation and configuration of a k8s + _NetworkPolicy resource_. + properties: + enabled: + type: boolean + description: | + Toggle the creation of the NetworkPolicy resource targeting this + pod, and by doing so, restricting its communication to only what + is explicitly allowed in the NetworkPolicy. + ingress: + type: array + description: | + Additional ingress rules to add besides those that are required + for core functionality. + egress: + type: array + description: | + Additional egress rules to add besides those that are required for + core functionality and those added via + [`.egressAllowRules`](schema_hub.networkPolicy.egressAllowRules). + + ```{versionchanged} 2.0.0 + The default value changed from providing one very permissive rule + allowing all egress to providing no rule. The permissive rule is + still provided via + [`.egressAllowRules`](schema_hub.networkPolicy.egressAllowRules) + set to true though. + ``` + + As an example, below is a configuration that disables the more + broadly permissive `.privateIPs` egress allow rule for the hub + pod, and instead provides tightly scoped permissions to access a + specific k8s local service as identified by pod labels. + + ```yaml + hub: + networkPolicy: + egressAllowRules: + privateIPs: false + egress: + - to: + - podSelector: + matchLabels: + app: my-k8s-local-service + ports: + - protocol: TCP + port: 5978 + ``` + egressAllowRules: + type: object + additionalProperties: false + description: | + This is a set of predefined rules that when enabled will be added + to the NetworkPolicy list of egress rules. + + The resulting egress rules will be a composition of: + - rules specific for the respective pod(s) function within the + Helm chart + - rules based on enabled `egressAllowRules` flags + - rules explicitly specified by the user + + ```{note} + Each flag under this configuration will not render into a + dedicated rule in the NetworkPolicy resource, but instead combine + with the other flags to a reduced set of rules to avoid a + performance penalty. + ``` + + ```{versionadded} 2.0.0 + ``` + properties: + cloudMetadataServer: + type: boolean + description: | + Defaults to `false` for singleuser servers, but to `true` for + all other network policies. + + When enabled this rule allows the respective pod(s) to + establish outbound connections to the cloud metadata server. + + Note that the `nonPrivateIPs` rule is allowing all non Private + IP ranges but makes an exception for the cloud metadata + server, leaving this as the definitive configuration to allow + access to the cloud metadata server. + + ```{versionchanged} 3.0.0 + This configuration is not allowed to be configured true at the + same time as + [`singleuser.cloudMetadata.blockWithIptables`](schema_singleuser.cloudMetadata.blockWithIptables) + to avoid an ambiguous configuration. + ``` + dnsPortsCloudMetadataServer: + type: boolean + description: | + Defaults to `true` for all network policies. + + When enabled this rule allows the respective pod(s) to + establish outbound connections to the cloud metadata server + via port 53. + + Relying on this rule for the singleuser config should go hand + in hand with disabling + [`singleuser.cloudMetadata.blockWithIptables`](schema_singleuser.cloudMetadata.blockWithIptables) + to avoid an ambiguous configuration. + + Known situations when this rule can be relevant: + + - In GKE clusters with Cloud DNS that is reached at the + cloud metadata server's non-private IP. + + ```{note} + This chart doesn't know how to identify the DNS server that + pods will rely on due to variations between how k8s clusters + have been setup. Due to that, multiple rules are enabled by + default to ensure DNS connectivity. + ``` + + ```{versionadded} 3.0.0 + ``` + dnsPortsKubeSystemNamespace: + type: boolean + description: | + Defaults to `true` for all network policies. + + When enabled this rule allows the respective pod(s) to + establish outbound connections to pods in the kube-system + namespace via port 53. + + Known situations when this rule can be relevant: + + - GKE, EKS, AKS, and other clusters relying directly on + `kube-dns` or `coredns` pods in the `kube-system` namespace. + + ```{note} + This chart doesn't know how to identify the DNS server that + pods will rely on due to variations between how k8s clusters + have been setup. Due to that, multiple rules are enabled by + default to ensure DNS connectivity. + ``` + + ```{versionadded} 3.0.0 + ``` + dnsPortsPrivateIPs: + type: boolean + description: | + Defaults to `true` for all network policies. + + When enabled this rule allows the respective pod(s) to + establish outbound connections to private IPs via port 53. + + Known situations when this rule can be relevant: + + - GKE clusters relying on a DNS server indirectly via a a node + local DNS cache at an unknown private IP. + + ```{note} + This chart doesn't know how to identify the DNS server that + pods will rely on due to variations between how k8s clusters + have been setup. Due to that, multiple rules are enabled by + default to ensure DNS connectivity. + + ```{warning} + This rule is not expected to work in clusters relying on + Cilium to enforce the NetworkPolicy rules (includes GKE + clusters with Dataplane v2), this is due to a [known + limitation](https://github.com/cilium/cilium/issues/9209). + ``` + nonPrivateIPs: + type: boolean + description: | + Defaults to `true` for all network policies. + + When enabled this rule allows the respective pod(s) to + establish outbound connections to the non-private IP ranges + with the exception of the cloud metadata server. This means + respective pod(s) can establish connections to the internet + but not (say) an unsecured prometheus server running in the + same cluster. + privateIPs: + type: boolean + description: | + Defaults to `false` for singleuser servers, but to `true` for + all other network policies. + + Private IPs refer to the IP ranges `10.0.0.0/8`, + `172.16.0.0/12`, `192.168.0.0/16`. + + When enabled this rule allows the respective pod(s) to + establish outbound connections to the internal k8s cluster. + This means users can access the internet but not (say) an + unsecured prometheus server running in the same cluster. + + Since not all workloads in the k8s cluster may have + NetworkPolicies setup to restrict their incoming connections, + having this set to false can be a good defense against + malicious intent from someone in control of software in these + pods. + + If possible, try to avoid setting this to true as it gives + broad permissions that could be specified more directly via + the [`.egress`](schema_singleuser.networkPolicy.egress). + + ```{warning} + This rule is not expected to work in clusters relying on + Cilium to enforce the NetworkPolicy rules (includes GKE + clusters with Dataplane v2), this is due to a [known + limitation](https://github.com/cilium/cilium/issues/9209). + ``` + interNamespaceAccessLabels: + enum: [accept, ignore] + description: | + This configuration option determines if both namespaces and pods + in other namespaces, that have specific access labels, should be + accepted to allow ingress (set to `accept`), or, if the labels are + to be ignored when applied outside the local namespace (set to + `ignore`). + + The available access labels for respective NetworkPolicy resources + are: + + - `hub.jupyter.org/network-access-hub: "true"` (hub) + - `hub.jupyter.org/network-access-proxy-http: "true"` (proxy.chp, proxy.traefik) + - `hub.jupyter.org/network-access-proxy-api: "true"` (proxy.chp) + - `hub.jupyter.org/network-access-singleuser: "true"` (singleuser) + allowedIngressPorts: + type: array + description: | + A rule to allow ingress on these ports will be added no matter + what the origin of the request is. The default setting for + `proxy.chp` and `proxy.traefik`'s networkPolicy configuration is + `[http, https]`, while it is `[]` for other networkPolicies. + + Note that these port names or numbers target a Pod's port name or + number, not a k8s Service's port name or number. + db: + type: object + additionalProperties: false + properties: + type: + enum: [sqlite-pvc, sqlite-memory, mysql, postgres, other] + description: | + Type of database backend to use for the hub database. + + The Hub requires a persistent database to function, and this lets you specify + where it should be stored. + + The various options are: + + 1. **sqlite-pvc** + + Use an `sqlite` database kept on a persistent volume attached to the hub. + + By default, this disk is created by the cloud provider using + *dynamic provisioning* configured by a [storage + class](https://kubernetes.io/docs/concepts/storage/storage-classes/). + You can customize how this disk is created / attached by + setting various properties under `hub.db.pvc`. + + This is the default setting, and should work well for most cloud provider + deployments. + + 2. **sqlite-memory** + + Use an in-memory `sqlite` database. This should only be used for testing, + since the database is erased whenever the hub pod restarts - causing the hub + to lose all memory of users who had logged in before. + + When using this for testing, make sure you delete all other objects that the + hub has created (such as user pods, user PVCs, etc) every time the hub restarts. + Otherwise you might run into errors about duplicate resources. + + 3. **mysql** + + Use an externally hosted mysql database. + + You have to specify an sqlalchemy connection string for the mysql database you + want to connect to in `hub.db.url` if using this option. + + The general format of the connection string is: + ``` + mysql+pymysql://:@:/ + ``` + + The user specified in the connection string must have the rights to create + tables in the database specified. + + 4. **postgres** + + Use an externally hosted postgres database. + + You have to specify an sqlalchemy connection string for the postgres database you + want to connect to in `hub.db.url` if using this option. + + The general format of the connection string is: + ``` + postgresql+psycopg2://:@:/ + ``` + + The user specified in the connection string must have the rights to create + tables in the database specified. + + 5. **other** + + Use an externally hosted database of some kind other than mysql + or postgres. + + When using _other_, the database password must be passed as + part of [hub.db.url](schema_hub.db.url) as + [hub.db.password](schema_hub.db.password) will be ignored. + pvc: + type: object + additionalProperties: false + required: [storage] + description: | + Customize the Persistent Volume Claim used when `hub.db.type` is `sqlite-pvc`. + properties: + annotations: + type: object + additionalProperties: false + patternProperties: &labels-and-annotations-patternProperties + ".*": + type: string + description: | + Annotations to apply to the PVC containing the sqlite database. + + See [the Kubernetes + documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) + for more details about annotations. + selector: + type: object + additionalProperties: true + description: | + Label selectors to set for the PVC containing the sqlite database. + + Useful when you are using a specific PV, and want to bind to + that and only that. + + See [the Kubernetes + documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) + for more details about using a label selector for what PV to + bind to. + storage: + type: string + description: | + Size of disk to request for the database disk. + accessModes: + type: array + items: + type: [string, "null"] + description: | + AccessModes contains the desired access modes the volume + should have. See [the k8s + documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1) + for more information. + storageClassName: + type: [string, "null"] + description: | + Name of the StorageClass required by the claim. + + If this is a blank string it will be set to a blank string, + while if it is null, it will not be set at all. + subPath: + type: [string, "null"] + description: | + Path within the volume from which the container's volume + should be mounted. Defaults to "" (volume's root). + upgrade: + type: [boolean, "null"] + description: | + Users with external databases need to opt-in for upgrades of the + JupyterHub specific database schema if needed as part of a + JupyterHub version upgrade. + url: + type: [string, "null"] + description: | + Connection string when `hub.db.type` is mysql or postgres. + + See documentation for `hub.db.type` for more details on the format of this property. + password: + type: [string, "null"] + description: | + Password for the database when `hub.db.type` is mysql or postgres. + labels: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Extra labels to add to the hub pod. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) + to learn more about labels. + initContainers: + type: array + description: | + list of initContainers to be run with hub pod. See [Kubernetes Docs](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) + + ```yaml + hub: + initContainers: + - name: init-myservice + image: busybox:1.28 + command: ['sh', '-c', 'command1'] + - name: init-mydb + image: busybox:1.28 + command: ['sh', '-c', 'command2'] + ``` + extraEnv: + type: [object, array] + additionalProperties: true + description: | + Extra environment variables that should be set for the hub pod. + + Environment variables are usually used to: + - Pass parameters to some custom code in `hub.extraConfig`. + - Configure code running in the hub pod, such as an authenticator or + spawner. + + String literals with `$(ENV_VAR_NAME)` will be expanded by Kubelet which + is a part of Kubernetes. + + ```yaml + hub: + extraEnv: + # basic notation (for literal values only) + MY_ENV_VARS_NAME1: "my env var value 1" + + # explicit notation (the "name" field takes precedence) + HUB_NAMESPACE: + name: HUB_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + + # implicit notation (the "name" field is implied) + PREFIXED_HUB_NAMESPACE: + value: "my-prefix-$(HUB_NAMESPACE)" + SECRET_VALUE: + valueFrom: + secretKeyRef: + name: my-k8s-secret + key: password + ``` + + For more information, see the [Kubernetes EnvVar + specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#envvar-v1-core). + extraConfig: + type: object + additionalProperties: true + description: | + Arbitrary extra python based configuration that should be in `jupyterhub_config.py`. + + This is the *escape hatch* - if you want to configure JupyterHub to do something specific + that is not present here as an option, you can write the raw Python to do it here. + + extraConfig is a *dict*, so there can be multiple configuration + snippets under different names. The configuration sections are run in + alphabetical order based on the keys. + + Non-exhaustive examples of things you can do here: + - Subclass authenticator / spawner to do a custom thing + - Dynamically launch different images for different sets of images + - Inject an auth token from GitHub authenticator into user pod + - Anything else you can think of! + + Since this is usually a multi-line string, you want to format it using YAML's + [| operator](https://yaml.org/spec/1.2.2/#23-scalars). + + For example: + + ```yaml + hub: + extraConfig: + myConfig.py: | + c.JupyterHub.something = 'something' + c.Spawner.something_else = 'something else' + ``` + + ```{note} + No code validation is performed until JupyterHub loads it! If you make + a typo here, it will probably manifest itself as the hub pod failing + to start up and instead entering an `Error` state or the subsequent + `CrashLoopBackoff` state. + + To make use of your own programs linters etc, it would be useful to + not embed Python code inside a YAML file. To do that, consider using + [`hub.extraFiles`](schema_hub.extraFiles) and mounting a file to + `/usr/local/etc/jupyterhub/jupyterhub_config.d` in order to load your + extra configuration logic. + ``` + + fsGid: + type: [integer, "null"] + minimum: 0 + # This schema entry is needed to help us print a more helpful error + # message in NOTES.txt if hub.fsGid is set. + # + description: | + ```{note} + Removed in version 2.0.0. Use + [`hub.podSecurityContext`](schema_hub.podSecurityContext) and specify + `fsGroup` instead. + ``` + service: + type: object + additionalProperties: false + description: | + Object to configure the service the JupyterHub will be exposed on by the Kubernetes server. + properties: + type: + enum: [ClusterIP, NodePort, LoadBalancer, ExternalName] + description: | + The Kubernetes ServiceType to be used. + + The default type is `ClusterIP`. + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) + to learn more about service types. + ports: + type: object + additionalProperties: false + description: | + Object to configure the ports the hub service will be deployed on. + properties: + nodePort: + type: [integer, "null"] + minimum: 0 + description: | + The nodePort to deploy the hub service on. + annotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Kubernetes annotations to apply to the hub service. + extraPorts: + type: array + description: | + Extra ports to add to the Hub Service object besides `hub` / `8081`. + This should be an array that includes `name`, `port`, and `targetPort`. + See [Multi-port Services](https://kubernetes.io/docs/concepts/services-networking/service/#multi-port-services) for more details. + loadBalancerIP: + type: [string, "null"] + description: | + A public IP address the hub Kubernetes service should be exposed + on. To expose the hub directly is not recommended. Instead route + traffic through the proxy-public service towards the hub. + + pdb: &pdb-spec + type: object + additionalProperties: false + description: | + Configure a PodDisruptionBudget for this Deployment. + + These are disabled by default for our deployments that don't support + being run in parallel with multiple replicas. Only the user-scheduler + currently supports being run in parallel with multiple replicas. If + they are enabled for a Deployment with only one replica, they will + block `kubectl drain` of a node for example. + + Note that if you aim to block scaling down a node with the + hub/proxy/autohttps pod that would cause disruptions of the + deployment, then you should instead annotate the pods of the + Deployment [as described + here](https://github.com/kubernetes/autoscaler/blob/HEAD/cluster-autoscaler/FAQ.md#what-types-of-pods-can-prevent-ca-from-removing-a-node). + + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" + + See [the Kubernetes + documentation](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/) + for more details about disruptions. + properties: + enabled: + type: boolean + description: | + Decides if a PodDisruptionBudget is created targeting the + Deployment's pods. + maxUnavailable: + type: [integer, "null"] + description: | + The maximum number of pods that can be unavailable during + voluntary disruptions. + minAvailable: + type: [integer, "null"] + description: | + The minimum number of pods required to be available during + voluntary disruptions. + existingSecret: + type: [string, "null"] + description: | + This option allow you to provide the name of an existing k8s Secret to + use alongside of the chart managed k8s Secret. The content of this k8s + Secret will be merged with the chart managed k8s Secret, giving + priority to the self-managed k8s Secret. + + ```{warning} + 1. The self managed k8s Secret must mirror the structure in the chart + managed secret. + 2. [`proxy.secretToken`](schema_proxy.secretToken) (aka. + `hub.config.ConfigurableHTTPProxy.auth_token`) is only read from + the chart managed k8s Secret. + ``` + nodeSelector: &nodeSelector-spec + type: object + additionalProperties: true + description: | + An object with key value pairs representing labels. K8s Nodes are + required to have match all these labels for this Pod to scheduled on + them. + + ```yaml + disktype: ssd + nodetype: awesome + ``` + + See [the Kubernetes + documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) + for more details. + tolerations: &tolerations-spec + type: array + description: | + Tolerations allow a pod to be scheduled on nodes with taints. These + tolerations are additional tolerations to the tolerations common to + all pods of a their respective kind + ([scheduling.corePods.tolerations](schema_scheduling.corePods.tolerations), + [scheduling.userPods.tolerations](schema_scheduling.userPods.tolerations)). + + Pass this field an array of + [`Toleration`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#toleration-v1-core) + objects. + + See the [Kubernetes + docs](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) + for more info. + activeServerLimit: + type: [integer, "null"] + description: &jupyterhub-native-config-description | + JupyterHub native configuration, see the [JupyterHub + documentation](https://jupyterhub.readthedocs.io/en/stable/reference/api/app.html) + for more information. + allowNamedServers: + type: [boolean, "null"] + description: *jupyterhub-native-config-description + annotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + K8s annotations for the hub pod. + authenticatePrometheus: + type: [boolean, "null"] + description: *jupyterhub-native-config-description + concurrentSpawnLimit: + type: [integer, "null"] + description: *jupyterhub-native-config-description + consecutiveFailureLimit: + type: [integer, "null"] + description: *jupyterhub-native-config-description + podSecurityContext: &podSecurityContext-spec + additionalProperties: true + description: | + A k8s native specification of the pod's security context, see [the + documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core) + for details. + containerSecurityContext: &containerSecurityContext-spec + type: object + additionalProperties: true + description: | + A k8s native specification of the container's security context, see [the + documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core) + for details. + deploymentStrategy: + type: object + additionalProperties: false + properties: + rollingUpdate: + type: [string, "null"] + type: + type: [string, "null"] + description: | + JupyterHub does not support running in parallel, due to this we + default to using a deployment strategy of Recreate. + extraContainers: &extraContainers-spec + type: array + description: | + Additional containers for the Pod. Use a k8s native syntax. + extraVolumeMounts: &extraVolumeMounts-spec + type: array + description: | + Additional volume mounts for the Container. Use a k8s native syntax. + extraVolumes: &extraVolumes-spec + type: array + description: | + Additional volumes for the Pod. Use a k8s native syntax. + livenessProbe: &probe-spec + type: object + additionalProperties: true + required: [enabled] + if: + properties: + enabled: + const: true + then: + description: | + This config option is like the k8s native specification of a + container probe, except that it also supports an `enabled` boolean + flag. + + See [the k8s + documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#probe-v1-core) + for more details. + readinessProbe: *probe-spec + namedServerLimitPerUser: + type: [integer, "null"] + description: *jupyterhub-native-config-description + redirectToServer: + type: [boolean, "null"] + description: *jupyterhub-native-config-description + resources: &resources-spec + type: object + additionalProperties: true + description: | + A k8s native specification of resources, see [the + documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#resourcerequirements-v1-core). + lifecycle: &lifecycle-spec + type: object + additionalProperties: false + description: | + A k8s native specification of lifecycle hooks on the container, see [the + documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#lifecycle-v1-core). + properties: + postStart: + type: object + additionalProperties: true + preStop: + type: object + additionalProperties: true + services: + type: object + additionalProperties: true + description: | + This is where you register JupyterHub services. For details on how to + configure these services in this Helm chart just keep reading but for + details on services themselves instead read [JupyterHub's + documentation](https://jupyterhub.readthedocs.io/en/stable/reference/api/service.html). + + ```{note} + Only a selection of JupyterHub's configuration options that can be + configured for a service are documented below. All configuration set + here will be applied even if this Helm chart doesn't recognize it. + ``` + + JupyterHub's native configuration accepts a list of service objects, + this Helm chart only accept a dictionary where each key represents the + name of a service and the value is the actual service objects. + + When configuring JupyterHub services via this Helm chart, the `name` + field can be omitted as it can be implied by the dictionary key. + Further, the `api_token` field can be omitted as it will be + automatically generated as of version 1.1.0 of this Helm chart. + + If you have an external service that needs to access the automatically + generated api_token for the service, you can access it from the `hub` + k8s Secret part of this Helm chart under the key + `hub.services.my-service-config-key.apiToken`. + + Here is an example configuration of two services where the first + explicitly sets a name and api_token, while the second omits those and + lets the name be implied from the key name and the api_token be + automatically generated. + + ```yaml + hub: + services: + my-service-1: + admin: true + name: my-explicitly-set-service-name + api_token: my-explicitly-set-api_token + + # the name of the following service will be my-service-2 + # the api_token of the following service will be generated + my-service-2: {} + ``` + + If you develop a Helm chart depending on the JupyterHub Helm chart and + want to let some Pod's environment variable be populated with the + api_token of a service registered like above, then do something along + these lines. + + ```yaml + # ... container specification of a pod ... + env: + - name: MY_SERVICE_1_API_TOKEN + valueFrom: + secretKeyRef: + # Don't hardcode the name, use the globally accessible + # named templates part of the JupyterHub Helm chart. + name: {{ include "jupyterhub.hub.fullname" . }} + # Note below the use of the configuration key my-service-1 + # rather than the explicitly set service name. + key: hub.services.my-service-1.apiToken + ``` + properties: + name: + type: string + description: | + The name can be implied via the key name under which this + service is configured, and is due to that allowed to be + omitted in this Helm chart configuration of JupyterHub. + admin: + type: boolean + command: + type: [string, array] + url: + type: string + api_token: + type: [string, "null"] + description: | + The api_token will be automatically generated if not + explicitly set. It will also be exposed in via a k8s Secret + part of this Helm chart under a specific key. + + See the documentation under + [`hub.services`](schema_hub.services) for details about this. + apiToken: + type: [string, "null"] + description: | + An alias for api_token provided for backward compatibility by + the JupyterHub Helm chart that will be transformed to + api_token. + loadRoles: + type: object + additionalProperties: true + description: | + This is where you should define JupyterHub roles and apply them to + JupyterHub users, groups, and services to grant them additional + permissions as defined in JupyterHub's RBAC system. + + Complement this documentation with [JupyterHub's + documentation](https://jupyterhub.readthedocs.io/en/stable/rbac/roles.html#defining-roles) + about `load_roles`. + + Note that while JupyterHub's native configuration `load_roles` accepts + a list of role objects, this Helm chart only accepts a dictionary where + each key represents the name of a role and the value is the actual + role object. + + ```yaml + hub: + loadRoles: + teacher: + description: Access to users' information and group membership + + # this role provides permissions to... + scopes: [users, groups] + + # this role will be assigned to... + users: [erik] + services: [grading-service] + groups: [teachers] + ``` + + When configuring JupyterHub roles via this Helm chart, the `name` + field can be omitted as it can be implied by the dictionary key. + shutdownOnLogout: + type: [boolean, "null"] + description: *jupyterhub-native-config-description + templatePaths: + type: array + description: *jupyterhub-native-config-description + templateVars: + type: object + additionalProperties: true + description: *jupyterhub-native-config-description + serviceAccount: &serviceAccount + type: object + required: [create] + additionalProperties: false + description: | + Configuration for a k8s ServiceAccount dedicated for use by the + specific pod which this configuration is nested under. + properties: + create: + type: boolean + description: | + Whether or not to create the `ServiceAccount` resource. + name: + type: ["string", "null"] + description: | + This configuration serves multiple purposes: + + - It will be the `serviceAccountName` referenced by related Pods. + - If `create` is set, the created ServiceAccount resource will be named like this. + - If [`rbac.create`](schema_rbac.create) is set, the associated (Cluster)RoleBindings will bind to this name. + + If not explicitly provided, a default name will be used. + annotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Kubernetes annotations to apply to the k8s ServiceAccount. + extraPodSpec: &extraPodSpec-spec + type: object + additionalProperties: true + description: | + Arbitrary extra k8s pod specification as a YAML object. The default + value of this setting is an empty object, i.e. no extra configuration. + The value of this property is augmented to the pod specification as-is. + + This is a powerful tool for expert k8s administrators with advanced + configuration requirements. This setting should only be used for + configuration that cannot be accomplished through the other settings. + Misusing this setting can break your deployment and/or compromise + your system security. + + This is one of four related settings for inserting arbitrary pod + specification: + + 1. hub.extraPodSpec + 2. proxy.chp.extraPodSpec + 3. proxy.traefik.extraPodSpec + 4. scheduling.userScheduler.extraPodSpec + + One real-world use of these settings is to enable host networking. For + example, to configure host networking for the hub pod, add the + following to your helm configuration values: + + ```yaml + hub: + extraPodSpec: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + ``` + + Likewise, to configure host networking for the proxy pod, add the + following: + + ```yaml + proxy: + chp: + extraPodSpec: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + ``` + + N.B. Host networking has special security implications and can easily + break your deployment. This is an example—not an endorsement. + + See [PodSpec](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec) + for the latest pod resource specification. + + proxy: + type: object + additionalProperties: false + properties: + chp: + type: object + additionalProperties: false + description: | + Configure the configurable-http-proxy (chp) pod managed by jupyterhub to route traffic + both to itself and to user pods. + properties: + revisionHistoryLimit: *revisionHistoryLimit + networkPolicy: *networkPolicy-spec + extraCommandLineFlags: + type: array + description: | + A list of strings to be added as command line options when + starting + [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy#command-line-options) + that will be expanded with Helm's template function `tpl` which + can render Helm template logic inside curly braces (`{{ ... }}`). + + ```yaml + proxy: + chp: + extraCommandLineFlags: + - "--auto-rewrite" + - "--custom-header {{ .Values.myCustomStuff }}" + ``` + + Note that these will be appended last, and if you provide the same + flag twice, the last flag will be used, which mean you can + override the default flag values as well. + extraEnv: + type: [object, array] + additionalProperties: true + description: | + Extra environment variables that should be set for the chp pod. + + Environment variables are usually used here to: + - override HUB_SERVICE_PORT or HUB_SERVICE_HOST default values + - set CONFIGPROXY_SSL_KEY_PASSPHRASE for setting passphrase of SSL keys + + String literals with `$(ENV_VAR_NAME)` will be expanded by Kubelet which + is a part of Kubernetes. + + ```yaml + proxy: + chp: + extraEnv: + # basic notation (for literal values only) + MY_ENV_VARS_NAME1: "my env var value 1" + + # explicit notation (the "name" field takes precedence) + CHP_NAMESPACE: + name: CHP_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + + # implicit notation (the "name" field is implied) + PREFIXED_CHP_NAMESPACE: + value: "my-prefix-$(CHP_NAMESPACE)" + SECRET_VALUE: + valueFrom: + secretKeyRef: + name: my-k8s-secret + key: password + ``` + + For more information, see the [Kubernetes EnvVar + specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#envvar-v1-core). + pdb: *pdb-spec + nodeSelector: *nodeSelector-spec + tolerations: *tolerations-spec + containerSecurityContext: *containerSecurityContext-spec + image: *image-spec + livenessProbe: *probe-spec + readinessProbe: *probe-spec + resources: *resources-spec + defaultTarget: + type: [string, "null"] + description: | + Override the URL for the default routing target for the proxy. + Defaults to JupyterHub itself. + This will generally only have an effect while JupyterHub is not running, + as JupyterHub adds itself as the default target after it starts. + errorTarget: + type: [string, "null"] + description: | + Override the URL for the error target for the proxy. + Defaults to JupyterHub itself. + Useful to reduce load on the Hub + or produce more informative error messages than the Hub's default, + e.g. in highly customized deployments such as BinderHub. + See Configurable HTTP Proxy for details on implementing an error target. + extraPodSpec: *extraPodSpec-spec + secretToken: + type: [string, "null"] + description: | + ```{note} + As of version 1.0.0 this will automatically be generated and there is + no need to set it manually. + + If you wish to reset a generated key, you can use `kubectl edit` on + the k8s Secret typically named `hub` and remove the + `hub.config.ConfigurableHTTPProxy.auth_token` entry in the k8s Secret, + then perform a new `helm upgrade`. + ``` + + A 32-byte cryptographically secure randomly generated string used to + secure communications between the hub pod and the proxy pod running a + [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy) + instance. + + ```sh + # to generate a value, run + openssl rand -hex 32 + ``` + + Changing this value will cause the proxy and hub pods to restart. It is good security + practice to rotate these values over time. If this secret leaks, *immediately* change + it to something else, or user data can be compromised. + service: + type: object + additionalProperties: false + description: | + Configuration of the k8s Service `proxy-public` which either will + point to the `autohttps` pod running Traefik for TLS termination, or + the `proxy` pod running ConfigurableHTTPProxy. Incoming traffic from + users on the internet should always go through this k8s Service. + + When this service targets the `autohttps` pod which then routes to the + `proxy` pod, a k8s Service named `proxy-http` will be added targeting + the `proxy` pod and only accepting HTTP traffic on port 80. + properties: + type: + enum: [ClusterIP, NodePort, LoadBalancer, ExternalName] + description: | + Default `LoadBalancer`. + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) + to learn more about service types. + labels: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Extra labels to add to the proxy service. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) + to learn more about labels. + annotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Annotations to apply to the service that is exposing the proxy. + + See [the Kubernetes + documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) + for more details about annotations. + nodePorts: + type: object + additionalProperties: false + description: | + Object to set NodePorts to expose the service on for http and https. + + See [the Kubernetes + documentation](https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport) + for more details about NodePorts. + properties: + http: + type: [integer, "null"] + description: | + The HTTP port the proxy-public service should be exposed on. + https: + type: [integer, "null"] + description: | + The HTTPS port the proxy-public service should be exposed on. + disableHttpPort: + type: boolean + description: | + Default `false`. + + If `true`, port 80 for incoming HTTP traffic will no longer be exposed. This should not be used with `proxy.https.type=letsencrypt` or `proxy.https.enabled=false` as it would remove the only exposed port. + extraPorts: + type: array + description: | + Extra ports the k8s Service should accept incoming traffic on, + which will be redirected to either the `autohttps` pod (treafik) + or the `proxy` pod (chp). + + See [the Kubernetes + documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#serviceport-v1-core) + for the structure of the items in this list. + loadBalancerIP: + type: [string, "null"] + description: | + The public IP address the proxy-public Kubernetes service should + be exposed on. This entry will end up at the configurable proxy + server that JupyterHub manages, which will direct traffic to user + pods at the `/user` path and the hub pod at the `/hub` path. + + Set this if you want to use a fixed external IP address instead of + a dynamically acquired one. This is relevant if you have a domain + name that you want to point to a specific IP and want to ensure it + doesn't change. + loadBalancerSourceRanges: + type: array + description: | + A list of IP CIDR ranges that are allowed to access the load balancer service. + Defaults to allowing everyone to access it. + https: + type: object + additionalProperties: false + description: | + Object for customizing the settings for HTTPS used by the JupyterHub's proxy. + For more information on configuring HTTPS for your JupyterHub, see the [HTTPS section in our security guide](https) + properties: + enabled: + type: [boolean, "null"] + description: | + Indicator to set whether HTTPS should be enabled or not on the proxy. Defaults to `true` if the https object is provided. + type: + enum: [null, "", letsencrypt, manual, offload, secret] + description: | + The type of HTTPS encryption that is used. + Decides on which ports and network policies are used for communication via HTTPS. Setting this to `secret` sets the type to manual HTTPS with a secret that has to be provided in the `https.secret` object. + Defaults to `letsencrypt`. + letsencrypt: + type: object + additionalProperties: false + properties: + contactEmail: + type: [string, "null"] + description: | + The contact email to be used for automatically provisioned HTTPS certificates by Let's Encrypt. For more information see [Set up automatic HTTPS](setup-automatic-https). + Required for automatic HTTPS. + acmeServer: + type: [string, "null"] + description: | + Let's Encrypt is one of various ACME servers that can provide + a certificate, and by default their production server is used. + + Let's Encrypt staging: https://acme-staging-v02.api.letsencrypt.org/directory + Let's Encrypt production: acmeServer: https://acme-v02.api.letsencrypt.org/directory + manual: + type: object + additionalProperties: false + description: | + Object for providing own certificates for manual HTTPS configuration. To be provided when setting `https.type` to `manual`. + See [Set up manual HTTPS](setup-manual-https) + properties: + key: + type: [string, "null"] + description: | + The RSA private key to be used for HTTPS. + To be provided in the form of + + ``` + key: | + -----BEGIN RSA PRIVATE KEY----- + ... + -----END RSA PRIVATE KEY----- + ``` + cert: + type: [string, "null"] + description: | + The certificate to be used for HTTPS. + To be provided in the form of + + ``` + cert: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + ``` + secret: + type: object + additionalProperties: false + description: | + Secret to be provided when setting `https.type` to `secret`. + properties: + name: + type: [string, "null"] + description: | + Name of the secret + key: + type: [string, "null"] + description: | + Path to the private key to be used for HTTPS. + Example: `'tls.key'` + crt: + type: [string, "null"] + description: | + Path to the certificate to be used for HTTPS. + Example: `'tls.crt'` + hosts: + type: array + description: | + You domain in list form. + Required for automatic HTTPS. See [Set up automatic HTTPS](setup-automatic-https). + To be provided like: + ``` + hosts: + - + ``` + traefik: + type: object + additionalProperties: false + description: | + Configure the traefik proxy used to terminate TLS when 'autohttps' is enabled + properties: + revisionHistoryLimit: *revisionHistoryLimit + labels: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Extra labels to add to the traefik pod. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) + to learn more about labels. + networkPolicy: *networkPolicy-spec + extraInitContainers: + type: array + description: | + list of extraInitContainers to be run with traefik pod, after the containers set in the chart. See [Kubernetes Docs](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) + + ```yaml + proxy: + traefik: + extraInitContainers: + - name: init-myservice + image: busybox:1.28 + command: ['sh', '-c', 'command1'] + - name: init-mydb + image: busybox:1.28 + command: ['sh', '-c', 'command2'] + ``` + extraEnv: + type: [object, array] + additionalProperties: true + description: | + Extra environment variables that should be set for the traefik pod. + + Environment Variables here may be used to configure traefik. + + String literals with `$(ENV_VAR_NAME)` will be expanded by Kubelet which + is a part of Kubernetes. + + ```yaml + proxy: + traefik: + extraEnv: + # basic notation (for literal values only) + MY_ENV_VARS_NAME1: "my env var value 1" + + # explicit notation (the "name" field takes precedence) + TRAEFIK_NAMESPACE: + name: TRAEFIK_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + + # implicit notation (the "name" field is implied) + PREFIXED_TRAEFIK_NAMESPACE: + value: "my-prefix-$(TRAEFIK_NAMESPACE)" + SECRET_VALUE: + valueFrom: + secretKeyRef: + name: my-k8s-secret + key: password + ``` + + For more information, see the [Kubernetes EnvVar + specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#envvar-v1-core). + pdb: *pdb-spec + nodeSelector: *nodeSelector-spec + tolerations: *tolerations-spec + containerSecurityContext: *containerSecurityContext-spec + extraDynamicConfig: + type: object + additionalProperties: true + description: | + This refers to traefik's post-startup configuration. + + This Helm chart already provide such configuration, so this is a + place where you can merge in additional configuration. If you are + about to use this configuration, you may want to inspect the + default configuration declared + [here](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/HEAD/jupyterhub/templates/proxy/autohttps/_configmap-dynamic.yaml). + extraPorts: + type: array + description: | + Extra ports for the traefik container within the autohttps pod + that you would like to expose, formatted in a k8s native way. + extraStaticConfig: + type: object + additionalProperties: true + description: | + This refers to traefik's startup configuration. + + This Helm chart already provide such configuration, so this is a + place where you can merge in additional configuration. If you are + about to use this configuration, you may want to inspect the + default configuration declared + [here](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/HEAD/jupyterhub/templates/proxy/autohttps/_configmap-traefik.yaml). + extraVolumes: *extraVolumes-spec + extraVolumeMounts: *extraVolumeMounts-spec + hsts: + type: object + additionalProperties: false + required: [includeSubdomains, maxAge, preload] + description: | + This section regards a HTTP Strict-Transport-Security (HSTS) + response header. It can act as a request for a visiting web + browsers to enforce HTTPS on their end in for a given time into + the future, and optionally also for future requests to subdomains. + + These settings relate to traefik configuration which we use as a + TLS termination proxy. + + See [Mozilla's + documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) + for more information. + properties: + includeSubdomains: + type: boolean + maxAge: + type: integer + preload: + type: boolean + image: *image-spec + resources: *resources-spec + serviceAccount: *serviceAccount + extraPodSpec: *extraPodSpec-spec + labels: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + K8s labels for the proxy pod. + + ```{note} + For consistency, this should really be located under + proxy.chp.labels but isn't for historical reasons. + ``` + annotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + K8s annotations for the proxy pod. + + ```{note} + For consistency, this should really be located under + proxy.chp.annotations but isn't for historical reasons. + ``` + deploymentStrategy: + type: object + additionalProperties: false + properties: + rollingUpdate: + type: [string, "null"] + type: + type: [string, "null"] + description: | + While the proxy pod running + [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy) + could run in parallel, two instances running in parallel wouldn't + both receive updates from JupyterHub regarding how it should route + traffic. Due to this we default to using a deployment strategy of + Recreate instead of RollingUpdate. + secretSync: + type: object + additionalProperties: false + description: | + This configuration section refers to configuration of the sidecar + container in the autohttps pod running next to its traefik container + responsible for TLS termination. + + The purpose of this container is to store away and load TLS + certificates from a k8s Secret. The TLS certificates are acquired by + the ACME client (LEGO) that is running within the traefik container, + where traefik is using them for TLS termination. + properties: + containerSecurityContext: *containerSecurityContext-spec + image: *image-spec + resources: *resources-spec + + singleuser: + type: object + additionalProperties: false + description: | + Options for customizing the environment that is provided to the users after they log in. + properties: + networkPolicy: *networkPolicy-spec + podNameTemplate: + type: [string, "null"] + description: | + Passthrough configuration for + [KubeSpawner.pod_name_template](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.pod_name_template). + cpu: + type: object + additionalProperties: false + description: | + Set CPU limits & guarantees that are enforced for each user. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) + for more info. + properties: + limit: + type: [number, "null"] + guarantee: + type: [number, "null"] + memory: + type: object + additionalProperties: false + description: | + Set Memory limits & guarantees that are enforced for each user. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) + for more info. + properties: + limit: + type: [number, string, "null"] + guarantee: + type: [number, string, "null"] + description: | + Note that this field is referred to as *requests* by the Kubernetes API. + image: *image-spec + initContainers: + type: array + description: | + list of initContainers to be run every singleuser pod. See [Kubernetes Docs](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) + + ```yaml + singleuser: + initContainers: + - name: init-myservice + image: busybox:1.28 + command: ['sh', '-c', 'command1'] + - name: init-mydb + image: busybox:1.28 + command: ['sh', '-c', 'command2'] + ``` + profileList: + type: array + description: | + For more information about the profile list, see [KubeSpawner's + documentation](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner) + as this is simply a passthrough to that configuration. + + ```{note} + The image-pullers are aware of the overrides of images in + `singleuser.profileList` but they won't be if you configure it in + JupyterHub's configuration of '`c.KubeSpawner.profile_list`. + ``` + + ```yaml + singleuser: + profileList: + - display_name: "Default: Shared, 8 CPU cores" + description: "Your code will run on a shared machine with CPU only." + default: True + - display_name: "Personal, 4 CPU cores & 26GB RAM, 1 NVIDIA Tesla K80 GPU" + description: "Your code will run a personal machine with a GPU." + kubespawner_override: + extra_resource_limits: + nvidia.com/gpu: "1" + ``` + extraFiles: *extraFiles + extraEnv: + type: [object, array] + additionalProperties: true + description: | + Extra environment variables that should be set for the user pods. + + String literals with `$(ENV_VAR_NAME)` will be expanded by Kubelet which + is a part of Kubernetes. Note that the user pods will already have + access to a set of environment variables that you can use, like + `JUPYTERHUB_USER` and `JUPYTERHUB_HOST`. For more information about these + inspect [this source + code](https://github.com/jupyterhub/jupyterhub/blob/cc8e7806530466dce8968567d1bbd2b39a7afa26/jupyterhub/spawner.py#L763). + + ```yaml + singleuser: + extraEnv: + # basic notation (for literal values only) + MY_ENV_VARS_NAME1: "my env var value 1" + + # explicit notation (the "name" field takes precedence) + USER_NAMESPACE: + name: USER_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + + # implicit notation (the "name" field is implied) + PREFIXED_USER_NAMESPACE: + value: "my-prefix-$(USER_NAMESPACE)" + SECRET_VALUE: + valueFrom: + secretKeyRef: + name: my-k8s-secret + key: password + ``` + + For more information, see the [Kubernetes EnvVar + specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#envvar-v1-core). + nodeSelector: *nodeSelector-spec + extraTolerations: *tolerations-spec + extraNodeAffinity: + type: object + additionalProperties: false + description: | + Affinities describe where pods prefer or require to be scheduled, they + may prefer or require a node where they are to be scheduled to have a + certain label (node affinity). They may also require to be scheduled + in proximity or with a lack of proximity to another pod (pod affinity + and anti pod affinity). + + See the [Kubernetes + docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) + for more info. + properties: + required: + type: array + description: | + Pass this field an array of + [`NodeSelectorTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#nodeselectorterm-v1-core) + objects. + preferred: + type: array + description: | + Pass this field an array of + [`PreferredSchedulingTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#preferredschedulingterm-v1-core) + objects. + extraPodAffinity: + type: object + additionalProperties: false + description: | + See the description of `singleuser.extraNodeAffinity`. + properties: + required: + type: array + description: | + Pass this field an array of + [`PodAffinityTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podaffinityterm-v1-core) + objects. + preferred: + type: array + description: | + Pass this field an array of + [`WeightedPodAffinityTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#weightedpodaffinityterm-v1-core) + objects. + extraPodAntiAffinity: + type: object + additionalProperties: false + description: | + See the description of `singleuser.extraNodeAffinity`. + properties: + required: + type: array + description: | + Pass this field an array of + [`PodAffinityTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podaffinityterm-v1-core) + objects. + preferred: + type: array + description: | + Pass this field an array of + [`WeightedPodAffinityTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#weightedpodaffinityterm-v1-core) + objects. + cloudMetadata: + type: object + additionalProperties: false + required: [blockWithIptables, ip] + description: | + Please refer to dedicated section in [the Helm chart + documentation](block-metadata-iptables) for more information about + this. + properties: + blockWithIptables: + type: boolean + ip: + type: string + + cmd: + type: [array, string, "null"] + description: | + Passthrough configuration for + [KubeSpawner.cmd](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.cmd). + The default is "jupyterhub-singleuser". + Use `cmd: null` to launch a custom CMD from the image, + which must launch jupyterhub-singleuser or an equivalent process eventually. + For example: Jupyter's docker-stacks images. + defaultUrl: + type: [string, "null"] + description: | + Passthrough configuration for + [KubeSpawner.default_url](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.default_url). + # FIXME: name mismatch, named events_enabled in kubespawner + events: + type: [boolean, "null"] + description: | + Passthrough configuration for + [KubeSpawner.events_enabled](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.events_enabled). + extraAnnotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Passthrough configuration for + [KubeSpawner.extra_annotations](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_annotations). + extraContainers: + type: array + description: | + Passthrough configuration for + [KubeSpawner.extra_containers](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_containers). + extraLabels: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Passthrough configuration for + [KubeSpawner.extra_labels](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_labels). + extraPodConfig: + type: object + additionalProperties: true + description: | + Passthrough configuration for + [KubeSpawner.extra_pod_config](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_pod_config). + extraResource: + type: object + additionalProperties: false + properties: + # FIXME: name mismatch, named extra_resource_guarantees in kubespawner + guarantees: + type: object + additionalProperties: true + description: | + Passthrough configuration for + [KubeSpawner.extra_resource_guarantees](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_resource_guarantees). + # FIXME: name mismatch, named extra_resource_limits in kubespawner + limits: + type: object + additionalProperties: true + description: | + Passthrough configuration for + [KubeSpawner.extra_resource_limits](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_resource_limits). + fsGid: + type: [integer, "null"] + description: | + Passthrough configuration for + [KubeSpawner.fs_gid](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.fs_gid). + lifecycleHooks: + type: object + additionalProperties: false + description: | + Passthrough configuration for + [KubeSpawner.lifecycle_hooks](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.lifecycle_hooks). + properties: + postStart: + type: object + additionalProperties: true + preStop: + type: object + additionalProperties: true + networkTools: + type: object + additionalProperties: false + description: | + This configuration section refers to configuration of a conditionally + created initContainer for the user pods with a purpose to block a + specific IP address. + + This initContainer will be created if + [`singleuser.cloudMetadata.blockWithIptables`](schema_singleuser.cloudMetadata.blockWithIptables) + is set to true. + properties: + image: *image-spec + resources: *resources-spec + # FIXME: name mismatch, named service_account in kubespawner + serviceAccountName: + type: [string, "null"] + description: | + Passthrough configuration for + [KubeSpawner.service_account](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.service_account). + startTimeout: + type: [integer, "null"] + description: | + Passthrough configuration for + [KubeSpawner.start_timeout](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.start_timeout). + storage: + type: object + additionalProperties: false + required: [type, homeMountPath] + description: | + This section configures KubeSpawner directly to some extent but also + indirectly through Helm chart specific configuration options such as + [`singleuser.storage.type`](schema_singleuser.storage.type). + properties: + capacity: + type: [string, "null"] + description: | + Configures `KubeSpawner.storage_capacity`. + + See the [KubeSpawner + documentation](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html) + for more information. + dynamic: + type: object + additionalProperties: false + properties: + pvcNameTemplate: + type: [string, "null"] + description: | + Configures `KubeSpawner.pvc_name_template` which will be the + resource name of the PVC created by KubeSpawner for each user + if needed. + storageAccessModes: + type: array + items: + type: [string, "null"] + description: | + Configures `KubeSpawner.storage_access_modes`. + + See KubeSpawners documentation and [the k8s + documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes) + for more information. + storageClass: + type: [string, "null"] + description: | + Configures `KubeSpawner.storage_class`, which can be an + explicit StorageClass to dynamically provision storage for the + PVC that KubeSpawner will create. + + There is of a default StorageClass available in k8s clusters + for use if this is unspecified. + volumeNameTemplate: + type: [string, "null"] + description: | + Configures `KubeSpawner.volume_name_template`, which is the + name to reference from the containers volumeMounts section. + extraLabels: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Configures `KubeSpawner.storage_extra_labels`. Note that these + labels are set on the PVC during creation only and won't be + updated after creation. + extraVolumeMounts: *extraVolumeMounts-spec + extraVolumes: *extraVolumes-spec + homeMountPath: + type: string + description: | + The location within the container where the home folder storage + should be mounted. + static: + type: object + additionalProperties: false + properties: + pvcName: + type: [string, "null"] + description: | + Configures `KubeSpawner.pvc_claim_name` to reference + pre-existing storage. + subPath: + type: [string, "null"] + description: | + Configures the `subPath` field of a + `KubeSpawner.volume_mounts` entry added by the Helm chart. + + Path within the volume from which the container's volume + should be mounted. + type: + enum: [dynamic, static, none] + description: | + Decide if you want storage to be provisioned dynamically + (dynamic), or if you want to attach existing storage (static), or + don't want any storage to be attached (none). + allowPrivilegeEscalation: + type: [boolean, "null"] + description: | + Passthrough configuration for + [KubeSpawner.allow_privilege_escalation](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.allow_privilege_escalation). + uid: + type: [integer, "null"] + description: | + Passthrough configuration for + [KubeSpawner.uid](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.uid). + + This dictates as what user the main container will start up as. + + As an example of when this is needed, consider if you want to enable + sudo rights for some of your users. This can be done by starting up as + root, enabling it from the container in a startup script, and then + transitioning to the normal user. + + Default is 1000, set to null to use the container's default. + + scheduling: + type: object + additionalProperties: false + description: | + Objects for customizing the scheduling of various pods on the nodes and + related labels. + properties: + userScheduler: + type: object + additionalProperties: false + required: [enabled, plugins, pluginConfig, logLevel] + description: | + The user scheduler is making sure that user pods are scheduled + tight on nodes, this is useful for autoscaling of user node pools. + properties: + enabled: + type: boolean + description: | + Enables the user scheduler. + revisionHistoryLimit: *revisionHistoryLimit + replicas: + type: integer + description: | + You can have multiple schedulers to share the workload or improve + availability on node failure. + image: *image-spec + pdb: *pdb-spec + nodeSelector: *nodeSelector-spec + tolerations: *tolerations-spec + labels: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Extra labels to add to the userScheduler pods. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) + to learn more about labels. + annotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Extra annotations to add to the user-scheduler pods. + containerSecurityContext: *containerSecurityContext-spec + logLevel: + type: integer + description: | + Corresponds to the verbosity level of logging made by the + kube-scheduler binary running within the user-scheduler pod. + plugins: + type: object + additionalProperties: true + description: | + These plugins refers to kube-scheduler plugins as documented + [here](https://kubernetes.io/docs/reference/scheduling/config/). + + The user-scheduler is really just a kube-scheduler configured in a + way to pack users tight on nodes using these plugins. See + values.yaml for information about the default plugins. + pluginConfig: + type: array + description: | + Individually activated plugins can be configured further. + resources: *resources-spec + serviceAccount: *serviceAccount + extraPodSpec: *extraPodSpec-spec + podPriority: + type: object + additionalProperties: false + description: | + Pod Priority is used to allow real users evict user placeholder pods + that in turn by entering a Pending state can trigger a scale up by a + cluster autoscaler. + + Having this option enabled only make sense if the following conditions + are met: + + 1. A cluster autoscaler is installed. + 2. user-placeholer pods are configured to have a priority equal or + higher than the cluster autoscaler's "priority cutoff" so that the + cluster autoscaler scales up a node in advance for a pending user + placeholder pod. + 3. Normal user pods have a higher priority than the user-placeholder + pods. + 4. Image puller pods have a priority between normal user pods and + user-placeholder pods. + + Note that if the default priority cutoff if not configured on cluster + autoscaler, it will currently default to 0, and that in the future + this is meant to be lowered. If your cloud provider is installing the + cluster autoscaler for you, they may also configure this specifically. + + Recommended settings for a cluster autoscaler... + + ... with a priority cutoff of -10 (GKE): + + ```yaml + podPriority: + enabled: true + globalDefault: false + defaultPriority: 0 + imagePullerPriority: -5 + userPlaceholderPriority: -10 + ``` + + ... with a priority cutoff of 0: + + ```yaml + podPriority: + enabled: true + globalDefault: true + defaultPriority: 10 + imagePullerPriority: 5 + userPlaceholderPriority: 0 + ``` + properties: + enabled: + type: boolean + globalDefault: + type: boolean + description: | + Warning! This will influence all pods in the cluster. + + The priority a pod usually get is 0. But this can be overridden + with a PriorityClass resource if it is declared to be the global + default. This configuration option allows for the creation of such + global default. + defaultPriority: + type: integer + description: | + The actual value for the default pod priority. + imagePullerPriority: + type: integer + description: | + The actual value for the [hook|continuous]-image-puller pods' priority. + userPlaceholderPriority: + type: integer + description: | + The actual value for the user-placeholder pods' priority. + userPlaceholder: + type: object + additionalProperties: false + description: | + User placeholders simulate users but will thanks to PodPriority be + evicted by the cluster autoscaler if a real user shows up. In this way + placeholders allow you to create a headroom for the real users and + reduce the risk of a user having to wait for a node to be added. Be + sure to use the the continuous image puller as well along with + placeholders, so the images are also available when real users arrive. + + To test your setup efficiently, you can adjust the amount of user + placeholders with the following command: + ```sh + # Configure to have 3 user placeholders + kubectl scale sts/user-placeholder --replicas=3 + ``` + properties: + enabled: + type: boolean + image: *image-spec + revisionHistoryLimit: *revisionHistoryLimit + replicas: + type: integer + description: | + How many placeholder pods would you like to have? + labels: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Extra labels to add to the userPlaceholder pods. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) + to learn more about labels. + annotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Extra annotations to add to the placeholder pods. + resources: + type: object + additionalProperties: true + description: | + Unless specified here, the placeholder pods will request the same + resources specified for the real singleuser pods. + containerSecurityContext: *containerSecurityContext-spec + corePods: + type: object + additionalProperties: false + description: | + These settings influence the core pods like the hub, proxy and + user-scheduler pods. + These settings influence all pods considered core pods, namely: + + - hub + - proxy + - autohttps + - hook-image-awaiter + - user-scheduler + + By defaults, the tolerations are: + + - hub.jupyter.org/dedicated=core:NoSchedule + - hub.jupyter.org_dedicated=core:NoSchedule + + Note that tolerations set here are combined with the respective + components dedicated tolerations, and that `_` is available in case + `/` isn't allowed in the clouds tolerations. + properties: + tolerations: *tolerations-spec + nodeAffinity: + type: object + additionalProperties: false + description: | + Where should pods be scheduled? Perhaps on nodes with a certain + label is preferred or even required? + properties: + matchNodePurpose: + enum: [ignore, prefer, require] + description: | + Decide if core pods *ignore*, *prefer* or *require* to + schedule on nodes with this label: + ``` + hub.jupyter.org/node-purpose=core + ``` + userPods: + type: object + additionalProperties: false + description: | + These settings influence all pods considered user pods, namely: + + - user-placeholder + - hook-image-puller + - continuous-image-puller + - jupyter- + + By defaults, the tolerations are: + + - hub.jupyter.org/dedicated=core:NoSchedule + - hub.jupyter.org_dedicated=core:NoSchedule + + Note that tolerations set here are combined with the respective + components dedicated tolerations, and that `_` is available in case + `/` isn't allowed in the clouds tolerations. + properties: + tolerations: *tolerations-spec + nodeAffinity: + type: object + additionalProperties: false + description: | + Where should pods be scheduled? Perhaps on nodes with a certain + label is preferred or even required? + properties: + matchNodePurpose: + enum: [ignore, prefer, require] + description: | + Decide if user pods *ignore*, *prefer* or *require* to + schedule on nodes with this label: + ``` + hub.jupyter.org/node-purpose=user + ``` + + ingress: + type: object + additionalProperties: false + required: [enabled] + properties: + enabled: + type: boolean + description: | + Enable the creation of a Kubernetes Ingress to proxy-public service. + + See [Advanced Topics — Zero to JupyterHub with Kubernetes + 0.7.0 documentation](ingress) + for more details. + annotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Annotations to apply to the Ingress resource. + + See [the Kubernetes + documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) + for more details about annotations. + ingressClassName: + type: [string, "null"] + description: | + Maps directly to the Ingress resource's `spec.ingressClassName``. + + See [the Kubernetes + documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) + for more details. + hosts: + type: array + description: | + List of hosts to route requests to the proxy. + pathSuffix: + type: [string, "null"] + description: | + Suffix added to Ingress's routing path pattern. + + Specify `*` if your ingress matches path by glob pattern. + pathType: + enum: [Prefix, Exact, ImplementationSpecific] + description: | + The path type to use. The default value is 'Prefix'. + + See [the Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types) + for more details about path types. + tls: + type: array + description: | + TLS configurations for Ingress. + + See [the Kubernetes + documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) + for more details about annotations. + + prePuller: + type: object + additionalProperties: false + required: [hook, continuous] + properties: + revisionHistoryLimit: *revisionHistoryLimit + labels: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Extra labels to add to the pre puller job pods. + + See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) + to learn more about labels. + annotations: + type: object + additionalProperties: false + patternProperties: *labels-and-annotations-patternProperties + description: | + Annotations to apply to the hook and continous image puller pods. One example use case is to + disable istio sidecars which could interfere with the image pulling. + resources: + type: object + additionalProperties: true + description: | + These are standard Kubernetes resources with requests and limits for + cpu and memory. They will be used on the containers in the pods + pulling images. These should be set extremely low as the containers + shut down directly or is a pause container that just idles. + + They were made configurable as usage of ResourceQuota may require + containers in the namespace to have explicit resources set. + extraTolerations: *tolerations-spec + hook: + type: object + additionalProperties: false + required: [enabled] + description: | + See the [*optimization + section*](pulling-images-before-users-arrive) + for more details. + properties: + enabled: + type: boolean + pullOnlyOnChanges: + type: boolean + description: | + Pull only if changes have been made to the images to pull, or more + accurately if the hook-image-puller daemonset has changed in any + way. + podSchedulingWaitDuration: + description: | + The `hook-image-awaiter` has a criteria to await all the + `hook-image-puller` DaemonSet's pods to both schedule and finish + their image pulling. This flag can be used to relax this criteria + to instead only await the pods that _has already scheduled_ to + finish image pulling after a certain duration. + + The value of this is that sometimes the newly created + `hook-image-puller` pods cannot be scheduled because nodes are + full, and then it probably won't make sense to block a `helm + upgrade`. + + An infinite duration to wait for pods to schedule can be + represented by `-1`. This was the default behavior of version + 0.9.0 and earlier. + type: integer + nodeSelector: *nodeSelector-spec + tolerations: *tolerations-spec + containerSecurityContext: *containerSecurityContext-spec + image: *image-spec + resources: *resources-spec + serviceAccount: *serviceAccount + continuous: + type: object + additionalProperties: false + required: [enabled] + description: | + See the [*optimization + section*](pulling-images-before-users-arrive) + for more details. + + ```{note} + If used with a Cluster Autoscaler (an autoscaling node pool), also add + user-placeholders and enable pod priority. + ``` + properties: + enabled: + type: boolean + pullProfileListImages: + type: boolean + description: | + The singleuser.profileList configuration can provide a selection of + images. This option determines if all images identified there should + be pulled, both by the hook and continuous pullers. + + Images are looked for under `kubespawner_override`, and also + `profile_options.choices.kubespawner_override` since version 3.2.0. + + The reason to disable this, is that if you have for example 10 images + which start pulling in order from 1 to 10, a user that arrives and + wants to start a pod with image number 10 will need to wait for all + images to be pulled, and then it may be preferable to just let the + user arriving wait for a single image to be pulled on arrival. + extraImages: + type: object + additionalProperties: false + description: | + See the [*optimization section*](images-that-will-be-pulled) for more + details. + + ```yaml + prePuller: + extraImages: + my-extra-image-i-want-pulled: + name: jupyter/all-spark-notebook + tag: 2343e33dec46 + ``` + patternProperties: + ".*": + type: object + additionalProperties: false + required: [name, tag] + properties: + name: + type: string + tag: + type: string + containerSecurityContext: *containerSecurityContext-spec + pause: + type: object + additionalProperties: false + description: | + The image-puller pods rely on initContainer to pull all images, and + their actual container when they are done is just running a `pause` + container. These are settings for that pause container. + properties: + containerSecurityContext: *containerSecurityContext-spec + image: *image-spec + + custom: + type: object + additionalProperties: true + description: | + Additional values to pass to the Hub. + JupyterHub will not itself look at these, + but you can read values in your own custom config via `hub.extraConfig`. + For example: + + ```yaml + custom: + myHost: "https://example.horse" + hub: + extraConfig: + myConfig.py: | + c.MyAuthenticator.host = get_config("custom.myHost") + ``` + + cull: + type: object + additionalProperties: false + required: [enabled] + description: | + The + [jupyterhub-idle-culler](https://github.com/jupyterhub/jupyterhub-idle-culler) + can run as a JupyterHub managed service to _cull_ running servers. + properties: + enabled: + type: boolean + description: | + Enable/disable use of jupyter-idle-culler. + users: + type: [boolean, "null"] + description: See the `--cull-users` flag. + adminUsers: + type: [boolean, "null"] + description: See the `--cull-admin-users` flag. + removeNamedServers: + type: [boolean, "null"] + description: See the `--remove-named-servers` flag. + timeout: + type: [integer, "null"] + description: See the `--timeout` flag. + every: + type: [integer, "null"] + description: See the `--cull-every` flag. + concurrency: + type: [integer, "null"] + description: See the `--concurrency` flag. + maxAge: + type: [integer, "null"] + description: See the `--max-age` flag. + + debug: + type: object + additionalProperties: false + required: [enabled] + properties: + enabled: + type: boolean + description: | + Increases the loglevel throughout the resources in the Helm chart. + + rbac: + type: object + additionalProperties: false + required: [create] + properties: + enabled: + type: boolean + # This schema entry is needed to help us print a more helpful error + # message in NOTES.txt if hub.fsGid is set. + # + description: | + ````{note} + Removed in version 2.0.0. If you have been using `rbac.enable=false` + (strongly discouraged), then the equivalent configuration would be: + + ```yaml + rbac: + create: false + hub: + serviceAccount: + create: false + proxy: + traefik: + serviceAccount: + create: false + scheduling: + userScheduler: + serviceAccount: + create: false + prePuller: + hook: + serviceAccount: + create: false + ``` + ```` + create: + type: boolean + description: | + Decides if (Cluster)Role and (Cluster)RoleBinding resources are + created and bound to the configured serviceAccounts. + + global: + type: object + additionalProperties: true + properties: + safeToShowValues: + type: boolean + description: | + A flag that should only be set to true temporarily when experiencing a + deprecation message that contain censored content that you wish to + reveal. diff --git a/applications/jupyterhub/deploy/values.yaml b/applications/jupyterhub/deploy/values.yaml index 2f5cbca3c..41e108d69 100755 --- a/applications/jupyterhub/deploy/values.yaml +++ b/applications/jupyterhub/deploy/values.yaml @@ -1,4 +1,4 @@ -harness: +harness: # EDIT: CLOUDHARNESS subdomain: hub service: auto: false @@ -31,6 +31,11 @@ harness: fullnameOverride: "" nameOverride: +# enabled is ignored by the jupyterhub chart itself, but a chart depending on +# the jupyterhub chart conditionally can make use this config option as the +# condition. +enabled: + # custom can contain anything you want to pass to the hub pod, as all passed # Helm template values will be made available there. custom: {} @@ -54,10 +59,11 @@ imagePullSecrets: [] # ConfigurableHTTPProxy speaks with the actual ConfigurableHTTPProxy server in # the proxy pod. hub: + revisionHistoryLimit: config: JupyterHub: admin_access: true - authenticator_class: keycloak + authenticator_class: keycloak # EDIT: CLOUDHARNESS service: type: ClusterIP annotations: {} @@ -68,7 +74,6 @@ hub: baseUrl: / cookieSecret: initContainers: [] - fsGid: 1000 nodeSelector: {} tolerations: [] concurrentSpawnLimit: 64 @@ -106,37 +111,38 @@ hub: extraVolumes: [] extraVolumeMounts: [] image: - name: jupyterhub/k8s-hub - tag: "1.1.3" + name: quay.io/jupyterhub/k8s-hub + tag: "3.2.1" pullPolicy: pullSecrets: [] resources: {} + podSecurityContext: + fsGroup: 1000 containerSecurityContext: runAsUser: 1000 runAsGroup: 1000 allowPrivilegeEscalation: false lifecycle: {} + loadRoles: {} services: {} pdb: enabled: false maxUnavailable: minAvailable: 1 networkPolicy: - enabled: false + enabled: true ingress: [] - ## egress for JupyterHub already includes Kubernetes internal DNS and - ## access to the proxy, but can be restricted further, but ensure to allow - ## access to the Kubernetes API server that couldn't be pinned ahead of - ## time. - ## - ## ref: https://stackoverflow.com/a/59016417/2220152 - egress: - - to: - - ipBlock: - cidr: 0.0.0.0/0 + egress: [] + egressAllowRules: + cloudMetadataServer: true + dnsPortsCloudMetadataServer: true + dnsPortsKubeSystemNamespace: true + dnsPortsPrivateIPs: true + nonPrivateIPs: true + privateIPs: true interNamespaceAccessLabels: ignore allowedIngressPorts: [] - allowNamedServers: true + allowNamedServers: true # EDIT: CLOUDHARNESS namedServerLimitPerUser: authenticatePrometheus: redirectToServer: @@ -163,11 +169,13 @@ hub: timeoutSeconds: 1 existingSecret: serviceAccount: + create: true + name: annotations: {} extraPodSpec: {} rbac: - enabled: true + create: true # proxy relates to the proxy pod, the proxy-public service, and the autohttps # pod and proxy-http service. @@ -202,7 +210,7 @@ proxy: rollingUpdate: # service relates to the proxy-public service service: - type: NodePort + type: NodePort # EDIT: CLOUDHARNESS labels: {} annotations: {} nodePorts: @@ -215,13 +223,17 @@ proxy: # chp relates to the proxy pod, which is responsible for routing traffic based # on dynamic configuration sent from JupyterHub to CHP's REST API. chp: + revisionHistoryLimit: containerSecurityContext: runAsUser: 65534 # nobody user runAsGroup: 65534 # nobody group allowPrivilegeEscalation: false image: - name: jupyterhub/configurable-http-proxy - tag: 4.5.0 # https://github.com/jupyterhub/configurable-http-proxy/releases + name: quay.io/jupyterhub/configurable-http-proxy + # tag is automatically bumped to new patch versions by the + # watch-dependencies.yaml workflow. + # + tag: "4.6.1" # https://github.com/jupyterhub/configurable-http-proxy/tags pullPolicy: pullSecrets: [] extraCommandLineFlags: [] @@ -229,11 +241,14 @@ proxy: enabled: true initialDelaySeconds: 60 periodSeconds: 10 + failureThreshold: 30 + timeoutSeconds: 3 readinessProbe: enabled: true initialDelaySeconds: 0 periodSeconds: 2 failureThreshold: 1000 + timeoutSeconds: 1 resources: {} defaultTarget: errorTarget: @@ -241,12 +256,16 @@ proxy: nodeSelector: {} tolerations: [] networkPolicy: - enabled: false + enabled: true ingress: [] - egress: - - to: - - ipBlock: - cidr: 0.0.0.0/0 + egress: [] + egressAllowRules: + cloudMetadataServer: true + dnsPortsCloudMetadataServer: true + dnsPortsKubeSystemNamespace: true + dnsPortsPrivateIPs: true + nonPrivateIPs: true + privateIPs: true interNamespaceAccessLabels: ignore allowedIngressPorts: [http, https] pdb: @@ -257,13 +276,17 @@ proxy: # traefik relates to the autohttps pod, which is responsible for TLS # termination when proxy.https.type=letsencrypt. traefik: + revisionHistoryLimit: containerSecurityContext: runAsUser: 65534 # nobody user runAsGroup: 65534 # nobody group allowPrivilegeEscalation: false image: name: traefik - tag: v2.4.11 # ref: https://hub.docker.com/_/traefik?tab=tags + # tag is automatically bumped to new patch versions by the + # watch-dependencies.yaml workflow. + # + tag: "v2.10.7" # ref: https://hub.docker.com/_/traefik?tab=tags pullPolicy: pullSecrets: [] hsts: @@ -272,6 +295,7 @@ proxy: maxAge: 15724800 # About 6 months resources: {} labels: {} + extraInitContainers: [] extraEnv: {} extraVolumes: [] extraVolumeMounts: [] @@ -283,10 +307,14 @@ proxy: networkPolicy: enabled: true ingress: [] - egress: - - to: - - ipBlock: - cidr: 0.0.0.0/0 + egress: [] + egressAllowRules: + cloudMetadataServer: true + dnsPortsCloudMetadataServer: true + dnsPortsKubeSystemNamespace: true + dnsPortsPrivateIPs: true + nonPrivateIPs: true + privateIPs: true interNamespaceAccessLabels: ignore allowedIngressPorts: [http, https] pdb: @@ -294,6 +322,8 @@ proxy: maxUnavailable: minAvailable: 1 serviceAccount: + create: true + name: annotations: {} extraPodSpec: {} secretSync: @@ -302,8 +332,8 @@ proxy: runAsGroup: 65534 # nobody group allowPrivilegeEscalation: false image: - name: jupyterhub/k8s-secret-sync - tag: "1.1.3" + name: quay.io/jupyterhub/k8s-secret-sync + tag: "3.2.1" pullPolicy: pullSecrets: [] resources: {} @@ -342,29 +372,27 @@ singleuser: preferred: [] networkTools: image: - name: jupyterhub/k8s-network-tools - tag: "1.1.3" + name: quay.io/jupyterhub/k8s-network-tools + tag: "3.2.1" pullPolicy: pullSecrets: [] + resources: {} cloudMetadata: # block set to true will append a privileged initContainer using the # iptables to block the sensitive metadata server at the provided ip. - blockWithIptables: false + blockWithIptables: true + ip: 169.254.169.254 networkPolicy: - enabled: false + enabled: true ingress: [] - egress: - # Required egress to communicate with the hub and DNS servers will be - # augmented to these egress rules. - # - # This default rule explicitly allows all outbound traffic from singleuser - # pods, except to a typical IP used to return metadata that can be used by - # someone with malicious intent. - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 169.254.169.254/32 + egress: [] + egressAllowRules: + cloudMetadataServer: false + dnsPortsCloudMetadataServer: true + dnsPortsKubeSystemNamespace: true + dnsPortsPrivateIPs: true + nonPrivateIPs: true + privateIPs: false interNamespaceAccessLabels: ignore allowedIngressPorts: [] events: true @@ -376,6 +404,7 @@ singleuser: lifecycleHooks: {} initContainers: [] extraContainers: [] + allowPrivilegeEscalation: false uid: 1000 fsGid: 100 serviceAccountName: @@ -387,29 +416,29 @@ singleuser: static: pvcName: subPath: "{username}" - capacity: 10Mi - homeMountPath: /home/workspace + capacity: 10Mi # EDIT: CLOUDHARNESS + homeMountPath: /home/workspace # EDIT: CLOUDHARNESS dynamic: storageClass: - pvcNameTemplate: jupyter-{username} - volumeNameTemplate: jupyter-{username} + pvcNameTemplate: jupyter-{username} # EDIT: CLOUDHARNESS + volumeNameTemplate: jupyter-{username} # EDIT: CLOUDHARNESS storageAccessModes: [ReadWriteOnce] image: - name: jupyter/base-notebook - tag: "hub-1.4.2" + name: quay.io/jupyterhub/k8s-singleuser-sample + tag: "3.2.1" pullPolicy: pullSecrets: [] startTimeout: 300 cpu: - limit: 0.4 - guarantee: 0.05 + limit: 0.4 # EDIT: CLOUDHARNESS + guarantee: 0.05 # EDIT: CLOUDHARNESS memory: - limit: 0.5G - guarantee: 0.1G + limit: 0.5G # EDIT: CLOUDHARNESS + guarantee: 0.1G # EDIT: CLOUDHARNESS extraResource: limits: {} guarantees: {} - cmd: /usr/local/bin/start-singleuser.sh + cmd: jupyterhub-singleuser defaultUrl: extraPodConfig: {} profileList: [] @@ -417,74 +446,146 @@ singleuser: # scheduling relates to the user-scheduler pods and user-placeholder pods. scheduling: userScheduler: - enabled: false + enabled: false # EDIT: CLOUDHARNESS + revisionHistoryLimit: replicas: 2 logLevel: 4 + # plugins are configured on the user-scheduler to make us score how we + # schedule user pods in a way to help us schedule on the most busy node. By + # doing this, we help scale down more effectively. It isn't obvious how to + # enable/disable scoring plugins, and configure them, to accomplish this. + # # plugins ref: https://kubernetes.io/docs/reference/scheduling/config/#scheduling-plugins-1 + # migration ref: https://kubernetes.io/docs/reference/scheduling/config/#scheduler-configuration-migrations + # plugins: score: + # These scoring plugins are enabled by default according to + # https://kubernetes.io/docs/reference/scheduling/config/#scheduling-plugins + # 2022-02-22. + # + # Enabled with high priority: + # - NodeAffinity + # - InterPodAffinity + # - NodeResourcesFit + # - ImageLocality + # Remains enabled with low default priority: + # - TaintToleration + # - PodTopologySpread + # - VolumeBinding + # Disabled for scoring: + # - NodeResourcesBalancedAllocation + # disabled: - - name: SelectorSpread - - name: TaintToleration - - name: PodTopologySpread + # We disable these plugins (with regards to scoring) to not interfere + # or complicate our use of NodeResourcesFit. - name: NodeResourcesBalancedAllocation - - name: NodeResourcesLeastAllocated # Disable plugins to be allowed to enable them again with a different # weight and avoid an error. - - name: NodePreferAvoidPods - name: NodeAffinity - name: InterPodAffinity + - name: NodeResourcesFit - name: ImageLocality enabled: - - name: NodePreferAvoidPods - weight: 161051 - name: NodeAffinity weight: 14631 - name: InterPodAffinity weight: 1331 - - name: NodeResourcesMostAllocated + - name: NodeResourcesFit weight: 121 - name: ImageLocality weight: 11 + pluginConfig: + # Here we declare that we should optimize pods to fit based on a + # MostAllocated strategy instead of the default LeastAllocated. + - name: NodeResourcesFit + args: + scoringStrategy: + resources: + - name: cpu + weight: 1 + - name: memory + weight: 1 + type: MostAllocated containerSecurityContext: runAsUser: 65534 # nobody user runAsGroup: 65534 # nobody group allowPrivilegeEscalation: false image: # IMPORTANT: Bumping the minor version of this binary should go hand in - # hand with an inspection of the user-scheduelrs RBAC resources - # that we have forked. - name: k8s.gcr.io/kube-scheduler - tag: v1.19.13 # ref: https://github.com/kubernetes/website/blob/main/content/en/releases/patch-releases.md + # hand with an inspection of the user-scheduelr's RBAC + # resources that we have forked in + # templates/scheduling/user-scheduler/rbac.yaml. + # + # Debugging advice: + # + # - Is configuration of kube-scheduler broken in + # templates/scheduling/user-scheduler/configmap.yaml? + # + # - Is the kube-scheduler binary's compatibility to work + # against a k8s api-server that is too new or too old? + # + # - You can update the GitHub workflow that runs tests to + # include "deploy/user-scheduler" in the k8s namespace report + # and reduce the user-scheduler deployments replicas to 1 in + # dev-config.yaml to get relevant logs from the user-scheduler + # pods. Inspect the "Kubernetes namespace report" action! + # + # - Typical failures are that kube-scheduler fails to search for + # resources via its "informers", and won't start trying to + # schedule pods before they succeed which may require + # additional RBAC permissions or that the k8s api-server is + # aware of the resources. + # + # - If "successfully acquired lease" can be seen in the logs, it + # is a good sign kube-scheduler is ready to schedule pods. + # + name: registry.k8s.io/kube-scheduler + # tag is automatically bumped to new patch versions by the + # watch-dependencies.yaml workflow. The minor version is pinned in the + # workflow, and should be updated there if a minor version bump is done + # here. We aim to stay around 1 minor version behind the latest k8s + # version. + # + tag: "v1.28.6" # ref: https://github.com/kubernetes/kubernetes/tree/master/CHANGELOG pullPolicy: pullSecrets: [] nodeSelector: {} tolerations: [] + labels: {} + annotations: {} pdb: enabled: true maxUnavailable: 1 minAvailable: resources: {} serviceAccount: + create: true + name: annotations: {} extraPodSpec: {} podPriority: enabled: false globalDefault: false defaultPriority: 0 + imagePullerPriority: -5 userPlaceholderPriority: -10 userPlaceholder: enabled: true image: - name: k8s.gcr.io/pause - # tag's can be updated by inspecting the output of the command: - # gcloud container images list-tags k8s.gcr.io/pause --sort-by=~tags + name: registry.k8s.io/pause + # tag is automatically bumped to new patch versions by the + # watch-dependencies.yaml workflow. # # If you update this, also update prePuller.pause.image.tag - tag: "3.5" + # + tag: "3.9" pullPolicy: pullSecrets: [] + revisionHistoryLimit: replicas: 0 + labels: {} + annotations: {} containerSecurityContext: runAsUser: 65534 # nobody user runAsGroup: 65534 # nobody group @@ -517,6 +618,8 @@ scheduling: # prePuller relates to the hook|continuous-image-puller DaemonsSets prePuller: + revisionHistoryLimit: + labels: {} annotations: {} resources: {} containerSecurityContext: @@ -530,8 +633,8 @@ prePuller: pullOnlyOnChanges: true # image and the configuration below relates to the hook-image-awaiter Job image: - name: jupyterhub/k8s-image-awaiter - tag: "1.1.3" + name: quay.io/jupyterhub/k8s-image-awaiter + tag: "3.2.1" pullPolicy: pullSecrets: [] containerSecurityContext: @@ -543,6 +646,8 @@ prePuller: tolerations: [] resources: {} serviceAccount: + create: true + name: annotations: {} continuous: enabled: true @@ -554,18 +659,20 @@ prePuller: runAsGroup: 65534 # nobody group allowPrivilegeEscalation: false image: - name: k8s.gcr.io/pause - # tag's can be updated by inspecting the output of the command: - # gcloud container images list-tags k8s.gcr.io/pause --sort-by=~tags + name: registry.k8s.io/pause + # tag is automatically bumped to new patch versions by the + # watch-dependencies.yaml workflow. # # If you update this, also update scheduling.userPlaceholder.image.tag - tag: "3.5" + # + tag: "3.9" pullPolicy: pullSecrets: [] ingress: enabled: false annotations: {} + ingressClassName: hosts: [] pathSuffix: pathType: Prefix @@ -581,7 +688,8 @@ ingress: cull: enabled: true users: false # --cull-users - removeNamedServers: true # --remove-named-servers + adminUsers: true # --cull-admin-users + removeNamedServers: true # EDIT: CLOUDHARNESS timeout: 3600 # --timeout every: 600 # --cull-every concurrency: 10 # --concurrency diff --git a/applications/jupyterhub/zero-to-jupyterhub-k8s b/applications/jupyterhub/zero-to-jupyterhub-k8s new file mode 160000 index 000000000..c92c12374 --- /dev/null +++ b/applications/jupyterhub/zero-to-jupyterhub-k8s @@ -0,0 +1 @@ +Subproject commit c92c12374795e84f36f5f16c4e8b8a448ad2f230 From cff3c6b7d85b0d6c3f99f3d84222eb6062bd3d85 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Sat, 20 Jan 2024 11:31:34 +0100 Subject: [PATCH 02/37] CH-110 jupyterhub update wip --- applications/jupyterhub/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/applications/jupyterhub/README.md b/applications/jupyterhub/README.md index d961d0347..d7d67d4d9 100755 --- a/applications/jupyterhub/README.md +++ b/applications/jupyterhub/README.md @@ -31,3 +31,13 @@ To support the pre pulling of task images see (https://github.com/MetaCell/cloud the template `templates/image-puller/_helpers-daemonset.tpl` has been changed (see line 167 and on) TODO: remember to implement/revise this code after you have updated/changed the templates of JupyterHub + +## How to update + +The helm chart is based on the [zero-to-jupyterhub](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/) helm chart. + +1. Run update.sh [TAG] # Do not use latest! +2. Restore from the diff files with EDIT: CLOUDHARNESS + +Customize notebook image: quay.io/jupyterhub/k8s-singleuser-sample:[TAG] + From 428d83d75b91cb956c6cf758cc87cb5ab4a25efa Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Sat, 20 Jan 2024 11:31:46 +0100 Subject: [PATCH 03/37] CH-110 jupyterhub update wip --- applications/jupyterhub/Dockerfile | 26 +- applications/jupyterhub/README.md | 3 +- .../deploy/resources/hub/jupyterhub_config.py | 1 + .../jupyterhub/deploy/resources/hub/z2jh.py | 1 + .../deploy/templates/_helpers-auth-rework.tpl | 4 +- .../jupyterhub/deploy/templates/_helpers.tpl | 2 +- applications/jupyterhub/update.patch | 5845 +++++++++++++++++ applications/jupyterhub/update.sh | 28 + deployment/codefresh-test-local.yaml | 439 +- 9 files changed, 6050 insertions(+), 299 deletions(-) create mode 100644 applications/jupyterhub/update.patch create mode 100644 applications/jupyterhub/update.sh diff --git a/applications/jupyterhub/Dockerfile b/applications/jupyterhub/Dockerfile index 8b279adc0..907ce6725 100755 --- a/applications/jupyterhub/Dockerfile +++ b/applications/jupyterhub/Dockerfile @@ -1,31 +1,39 @@ ARG CLOUDHARNESS_BASE FROM $CLOUDHARNESS_BASE as base -FROM jupyterhub/k8s-hub:1.1.3 +FROM quay.io/jupyterhub/k8s-hub:3.2.1 USER root COPY --from=base libraries/models/requirements.txt /libraries/models/requirements.txt -RUN pip install -r /libraries/models/requirements.txt +RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ + pip install -r /libraries/models/requirements.txt COPY --from=base libraries/cloudharness-common/requirements.txt /libraries/cloudharness-common/requirements.txt -RUN pip install -r /libraries/cloudharness-common/requirements.txt +RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ + pip install -r /libraries/cloudharness-common/requirements.txt COPY --from=base libraries/client/cloudharness_cli/requirements.txt /libraries/client/cloudharness_cli/requirements.txt -RUN pip install -r /libraries/client/cloudharness_cli/requirements.txt +RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ + pip install -r /libraries/client/cloudharness_cli/requirements.txt COPY --from=base libraries/models /libraries/models -RUN pip install -e /libraries/models +RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ + pip install -e /libraries/models COPY --from=base libraries/cloudharness-common /libraries/cloudharness-common COPY --from=base libraries/client/cloudharness_cli /libraries/client/cloudharness_cli # -RUN pip install -e /libraries/cloudharness-common -RUN pip install -e /libraries/client/cloudharness_cli +RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ + pip install -e /libraries/cloudharness-common +RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ + pip install -e /libraries/client/cloudharness_cli COPY src src -RUN pip install ./src/harness_jupyter -RUN pip install ./src/chauthenticator +RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ + pip install ./src/harness_jupyter +RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ + pip install ./src/chauthenticator USER jovyan diff --git a/applications/jupyterhub/README.md b/applications/jupyterhub/README.md index d7d67d4d9..9ad78d2fd 100755 --- a/applications/jupyterhub/README.md +++ b/applications/jupyterhub/README.md @@ -37,7 +37,8 @@ TODO: remember to implement/revise this code after you have updated/changed the The helm chart is based on the [zero-to-jupyterhub](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/) helm chart. 1. Run update.sh [TAG] # Do not use latest! -2. Restore from the diff files with EDIT: CLOUDHARNESS +2. Restore from the diff files with EDIT: CLOUDHARNESS. Use update.patch as a reference +3. 3. Update Dockerfile to use the same base image you see on values.yaml: hub/image Customize notebook image: quay.io/jupyterhub/k8s-singleuser-sample:[TAG] diff --git a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py index 8ec801ee5..5ebe20b5d 100755 --- a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py +++ b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py @@ -537,6 +537,7 @@ def camelCaseify(s): c.Authenticator.auto_login = True c.OAuthenticator.client_id = client_id c.OAuthenticator.client_secret = client_secret + c.OAuthenticator.allow_all = True c.GenericOAuthenticator.login_service = "CH" c.GenericOAuthenticator.username_key = "email" diff --git a/applications/jupyterhub/deploy/resources/hub/z2jh.py b/applications/jupyterhub/deploy/resources/hub/z2jh.py index fc368f64e..2fe0d25b8 100755 --- a/applications/jupyterhub/deploy/resources/hub/z2jh.py +++ b/applications/jupyterhub/deploy/resources/hub/z2jh.py @@ -119,6 +119,7 @@ def get_config(key, default=None): value = value[level] # EDIT: CLOUDHARNESS START + import re if value and isinstance(value, str): replace_var = re.search("{{.*?}}", value) if replace_var: diff --git a/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl b/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl index 3159d1033..e9d2b4f42 100644 --- a/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl +++ b/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl @@ -178,7 +178,7 @@ ldap.dn.user.useLookupName: LDAPAuthenticator.use_lookup_dn_username representing the old z2jh config, output the result in $c. */}} - {{- include "jupyterhub.authDep.remapOldToNew.mappable" (list $c .Values.apps.jupyterhub.apps.jupyterhub.global.safeToSho.Values.apps.jupyterhub. }} + {{- include "jupyterhub.authDep.remapOldToNew.mappable" (list $c .Values.apps.jupyterhub.apps.jupyterhub.global.safeToSho.Values.apps.jupyterhub) }} {{- $class_old_config_key := .Values.apps.jupyterhub.apps.jupyterhub.auth.type | default "" }} {{- /* ldap - github */}} {{- $class_new_entrypoint := "" }} {{- /* ldapauthenticator.LDAPAuthenticator - github */}} @@ -191,7 +191,7 @@ ldap.dn.user.useLookupName: LDAPAuthenticator.use_lookup_dn_username {{- /* UPDATE c dict explicitly with auth.custom.config */}} {{- if .Values.apps.jupyterhub.apps.jupyterhub.auth.custom.config }} {{- $custom_config := merge (dict) .Values.apps.jupyterhub.apps.jupyterhub.auth.custom.config }} - {{- if not .Values.apps.jupyterhub.apps.jupyterhub.global.safeToSho.Values.apps.jupyterhub.}} + {{- if not .Values.apps.jupyterhub.apps.jupyterhub.global.safeToSho.Values.apps.jupyterhub }} {{- range $key, $val := $custom_config }} {{- $_ := set $custom_config $key "***" }} {{- end }} diff --git a/applications/jupyterhub/deploy/templates/_helpers.tpl b/applications/jupyterhub/deploy/templates/_helpers.tpl index a20236395..1737f3d6e 100755 --- a/applications/jupyterhub/deploy/templates/_helpers.tpl +++ b/applications/jupyterhub/deploy/templates/_helpers.tpl @@ -194,7 +194,7 @@ component: {{ include "jupyterhub.componentLabel" . }} using "toYaml | fromYaml" in order to be able to use normal helm template functions on it. */}} - {{- $jupyterhub_values := .root.Values.apps.jupyterhub.}} + {{- $jupyterhub_values := .root.Values.apps.jupyterhub }} {{- if ne .root.Chart.Name "jupyterhub" }} {{- if .root.Values.apps.jupyterhub.jupyterhub }} {{- $jupyterhub_values = .root.Values.apps.jupyterhub.jupyterhub }} diff --git a/applications/jupyterhub/update.patch b/applications/jupyterhub/update.patch new file mode 100644 index 000000000..5241525b2 --- /dev/null +++ b/applications/jupyterhub/update.patch @@ -0,0 +1,5845 @@ +diff --git a/applications/jupyterhub/README.md b/applications/jupyterhub/README.md +index d961d03..d7d67d4 100755 +--- a/applications/jupyterhub/README.md ++++ b/applications/jupyterhub/README.md +@@ -31,3 +31,13 @@ To support the pre pulling of task images see (https://github.com/MetaCell/cloud + the template `templates/image-puller/_helpers-daemonset.tpl` has been changed (see line 167 and on) + + TODO: remember to implement/revise this code after you have updated/changed the templates of JupyterHub ++ ++## How to update ++ ++The helm chart is based on the [zero-to-jupyterhub](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/) helm chart. ++ ++1. Run update.sh [TAG] # Do not use latest! ++2. Restore from the diff files with EDIT: CLOUDHARNESS ++ ++Customize notebook image: quay.io/jupyterhub/k8s-singleuser-sample:[TAG] ++ +diff --git a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py +index d4b3cee..8ec801e 100755 +--- a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py ++++ b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py +@@ -1,9 +1,17 @@ ++# load the config object (satisfies linters) ++c = get_config() # noqa ++ ++import glob + import os + import re + import sys +-import logging + ++from jupyterhub.utils import url_path_join ++from kubernetes_asyncio import client + from tornado.httpclient import AsyncHTTPClient ++ ++#CLOUDHARNESS: EDIT START ++import logging + from kubernetes import client + from jupyterhub.utils import url_path_join + +@@ -12,7 +20,7 @@ try: + harness_hub() # activates harness hooks on jupyterhub + except Exception as e: + logging.error("could not import harness_jupyter", exc_info=True) +- ++# CLOUDHARNESS: EDIT END + + # Make sure that modules placed in the same directory as the jupyterhub config are added to the pythonpath + configuration_directory = os.path.dirname(os.path.realpath(__file__)) +@@ -20,39 +28,13 @@ sys.path.insert(0, configuration_directory) + + from z2jh import ( + get_config, +- set_config_if_not_none, + get_name, + get_name_env, + get_secret_value, ++ set_config_if_not_none, + ) + + +-print('Base url is', c.JupyterHub.get('base_url', '/')) +- +-# Configure JupyterHub to use the curl backend for making HTTP requests, +-# rather than the pure-python implementations. The default one starts +-# being too slow to make a large number of requests to the proxy API +-# at the rate required. +-AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient") +- +-c.JupyterHub.spawner_class = 'kubespawner.KubeSpawner' +- +-# Connect to a proxy running in a different pod +-c.ConfigurableHTTPProxy.api_url = 'http://{}:{}'.format(os.environ['PROXY_API_SERVICE_HOST'], int(os.environ['PROXY_API_SERVICE_PORT'])) +-c.ConfigurableHTTPProxy.should_start = False +- +-# Do not shut down user pods when hub is restarted +-c.JupyterHub.cleanup_servers = False +- +-# Check that the proxy has routes appropriately setup +-c.JupyterHub.last_activity_interval = 60 +- +-# Don't wait at all before redirecting a spawning user to the progress page +-c.JupyterHub.tornado_settings = { +- 'slow_spawn_timeout': 0, +-} +- +- + def camelCaseify(s): + """convert snake_case to camelCase + +@@ -173,6 +155,7 @@ for trait, cfg_key in ( + ("events_enabled", "events"), + ("extra_labels", None), + ("extra_annotations", None), ++ # ("allow_privilege_escalation", None), # Managed manually below + ("uid", None), + ("fs_gid", None), + ("service_account", "serviceAccountName"), +@@ -206,10 +189,19 @@ image = get_config("singleuser.image.name") + if image: + tag = get_config("singleuser.image.tag") + if tag: +- image = "{}:{}".format(image, tag) ++ image = f"{image}:{tag}" + + c.KubeSpawner.image = image + ++# allow_privilege_escalation defaults to False in KubeSpawner 2+. Since its a ++# property where None, False, and True all are valid values that users of the ++# Helm chart may want to set, we can't use the set_config_if_not_none helper ++# function as someone may want to override the default False value to None. ++# ++c.KubeSpawner.allow_privilege_escalation = get_config( ++ "singleuser.allowPrivilegeEscalation" ++) ++ + # Combine imagePullSecret.create (single), imagePullSecrets (list), and + # singleuser.image.pullSecrets (list). + image_pull_secrets = [] +@@ -255,7 +247,7 @@ if match_node_purpose: + pass + else: + raise ValueError( +- "Unrecognized value for matchNodePurpose: %r" % match_node_purpose ++ f"Unrecognized value for matchNodePurpose: {match_node_purpose}" + ) + + # Combine the common tolerations for user pods with singleuser tolerations +@@ -271,7 +263,7 @@ if storage_type == "dynamic": + pvc_name_template = get_config("singleuser.storage.dynamic.pvcNameTemplate") + c.KubeSpawner.pvc_name_template = pvc_name_template + volume_name_template = get_config("singleuser.storage.dynamic.volumeNameTemplate") +- c.KubeSpawner.storage_pvc_ensure = False ++ c.KubeSpawner.storage_pvc_ensure = True + set_config_if_not_none( + c.KubeSpawner, "storage_class", "singleuser.storage.dynamic.storageClass" + ) +@@ -354,41 +346,62 @@ c.KubeSpawner.volume_mounts.extend( + ) + + c.JupyterHub.services = [] ++c.JupyterHub.load_roles = [] + ++# jupyterhub-idle-culler's permissions are scoped to what it needs only, see ++# https://github.com/jupyterhub/jupyterhub-idle-culler#permissions. ++# + if get_config("cull.enabled", False): ++ jupyterhub_idle_culler_role = { ++ "name": "jupyterhub-idle-culler", ++ "scopes": [ ++ "list:users", ++ "read:users:activity", ++ "read:servers", ++ "delete:servers", ++ # "admin:users", # dynamically added if --cull-users is passed ++ ], ++ # assign the role to a jupyterhub service, so it gains these permissions ++ "services": ["jupyterhub-idle-culler"], ++ } ++ + cull_cmd = ["python3", "-m", "jupyterhub_idle_culler"] + base_url = c.JupyterHub.get("base_url", "/") + cull_cmd.append("--url=http://localhost:8081" + url_path_join(base_url, "hub/api")) + + cull_timeout = get_config("cull.timeout") + if cull_timeout: +- cull_cmd.append("--timeout=%s" % cull_timeout) ++ cull_cmd.append(f"--timeout={cull_timeout}") + + cull_every = get_config("cull.every") + if cull_every: +- cull_cmd.append("--cull-every=%s" % cull_every) ++ cull_cmd.append(f"--cull-every={cull_every}") + + cull_concurrency = get_config("cull.concurrency") + if cull_concurrency: +- cull_cmd.append("--concurrency=%s" % cull_concurrency) ++ cull_cmd.append(f"--concurrency={cull_concurrency}") + + if get_config("cull.users"): + cull_cmd.append("--cull-users") ++ jupyterhub_idle_culler_role["scopes"].append("admin:users") ++ ++ if not get_config("cull.adminUsers"): ++ cull_cmd.append("--cull-admin-users=false") + + if get_config("cull.removeNamedServers"): + cull_cmd.append("--remove-named-servers") + + cull_max_age = get_config("cull.maxAge") + if cull_max_age: +- cull_cmd.append("--max-age=%s" % cull_max_age) ++ cull_cmd.append(f"--max-age={cull_max_age}") + + c.JupyterHub.services.append( + { +- "name": "cull-idle", +- "admin": True, ++ "name": "jupyterhub-idle-culler", + "command": cull_cmd, + } + ) ++ c.JupyterHub.load_roles.append(jupyterhub_idle_culler_role) + + for key, service in get_config("hub.services", {}).items(): + # c.JupyterHub.services is a list of dicts, but +@@ -402,26 +415,44 @@ for key, service in get_config("hub.services", {}).items(): + + c.JupyterHub.services.append(service) + ++for key, role in get_config("hub.loadRoles", {}).items(): ++ # c.JupyterHub.load_roles is a list of dicts, but ++ # hub.loadRoles is a dict of dicts to make the config mergable ++ role.setdefault("name", key) ++ ++ c.JupyterHub.load_roles.append(role) ++ ++# respect explicit null command (distinct from unspecified) ++# this avoids relying on KubeSpawner.cmd's default being None ++_unspecified = object() ++specified_cmd = get_config("singleuser.cmd", _unspecified) ++if specified_cmd is not _unspecified: ++ c.Spawner.cmd = specified_cmd + +-set_config_if_not_none(c.Spawner, "cmd", "singleuser.cmd") + set_config_if_not_none(c.Spawner, "default_url", "singleuser.defaultUrl") + +-cloud_metadata = get_config("singleuser.cloudMetadata", {}) ++cloud_metadata = get_config("singleuser.cloudMetadata") + + if cloud_metadata.get("blockWithIptables") == True: + # Use iptables to block access to cloud metadata by default + network_tools_image_name = get_config("singleuser.networkTools.image.name") + network_tools_image_tag = get_config("singleuser.networkTools.image.tag") ++ network_tools_resources = get_config("singleuser.networkTools.resources") ++ ip = cloud_metadata["ip"] + ip_block_container = client.V1Container( + name="block-cloud-metadata", + image=f"{network_tools_image_name}:{network_tools_image_tag}", + command=[ + "iptables", +- "-A", ++ "--append", + "OUTPUT", +- "-d", +- cloud_metadata.get("ip", "169.254.169.254"), +- "-j", ++ "--protocol", ++ "tcp", ++ "--destination", ++ ip, ++ "--destination-port", ++ "80", ++ "--jump", + "DROP", + ], + security_context=client.V1SecurityContext( +@@ -429,6 +460,7 @@ if cloud_metadata.get("blockWithIptables") == True: + run_as_user=0, + capabilities=client.V1Capabilities(add=["NET_ADMIN"]), + ), ++ resources=network_tools_resources, + ) + + c.KubeSpawner.init_containers.append(ip_block_container) +@@ -438,17 +470,6 @@ if get_config("debug.enabled", False): + c.JupyterHub.log_level = "DEBUG" + c.Spawner.debug = True + +-# load /usr/local/etc/jupyterhub/jupyterhub_config.d config files +-config_dir = "/usr/local/etc/jupyterhub/jupyterhub_config.d" +-if os.path.isdir(config_dir): +- for file_path in sorted(glob.glob(f"{config_dir}/*.py")): +- file_name = os.path.basename(file_path) +- print(f"Loading {config_dir} config: {file_name}") +- with open(file_path) as f: +- file_content = f.read() +- # compiling makes debugging easier: https://stackoverflow.com/a/437857 +- exec(compile(source=file_content, filename=file_name, mode="exec")) +- + # load potentially seeded secrets + # + # NOTE: ConfigurableHTTPProxy.auth_token is set through an environment variable +@@ -471,11 +492,23 @@ for app, cfg in get_config("hub.config", {}).items(): + cfg.pop("keys", None) + c[app].update(cfg) + ++# load /usr/local/etc/jupyterhub/jupyterhub_config.d config files ++config_dir = "/usr/local/etc/jupyterhub/jupyterhub_config.d" ++if os.path.isdir(config_dir): ++ for file_path in sorted(glob.glob(f"{config_dir}/*.py")): ++ file_name = os.path.basename(file_path) ++ print(f"Loading {config_dir} config: {file_name}") ++ with open(file_path) as f: ++ file_content = f.read() ++ # compiling makes debugging easier: https://stackoverflow.com/a/437857 ++ exec(compile(source=file_content, filename=file_name, mode="exec")) ++ + # execute hub.extraConfig entries + for key, config_py in sorted(get_config("hub.extraConfig", {}).items()): +- print("Loading extra config: %s" % key) ++ print(f"Loading extra config: {key}") + exec(config_py) + ++# CLOUDHARNESS: EDIT START + # Allow switching authenticators easily + auth_type = get_config('hub.config.JupyterHub.authenticator_class') + email_domain = 'local' +@@ -525,4 +558,5 @@ set_config_if_not_none(c.Authenticator, 'whitelist', 'auth.whitelist.users') + c.apps = get_config('apps') + c.registry = get_config('registry') + c.domain = get_config('root.domain') +-c.namespace = get_config('root.namespace') +\ No newline at end of file ++c.namespace = get_config('root.namespace') ++# CLOUDHARNESS: EDIT END +\ No newline at end of file +diff --git a/applications/jupyterhub/deploy/resources/hub/z2jh.py b/applications/jupyterhub/deploy/resources/hub/z2jh.py +index 834a6b6..fc368f6 100755 +--- a/applications/jupyterhub/deploy/resources/hub/z2jh.py ++++ b/applications/jupyterhub/deploy/resources/hub/z2jh.py +@@ -3,15 +3,15 @@ Utility methods for use in jupyterhub_config.py and dynamic subconfigs. + + Methods here can be imported by extraConfig in values.yaml + """ +-from collections import Mapping +-from functools import lru_cache + import os +-import re ++from collections.abc import Mapping ++from functools import lru_cache + + import yaml + ++ + # memoize so we only load config once +-@lru_cache() ++@lru_cache + def _load_config(): + """Load the Helm chart configuration used to render the Helm templates of + the chart from a mounted k8s Secret, and merge in values from an optionally +@@ -27,6 +27,7 @@ def _load_config(): + cfg = _merge_dictionaries(cfg, values) + else: + print(f"No config at {path}") ++ # EDIT: CLOUDHARNESS START + path = f"/opt/cloudharness/resources/allvalues.yaml" + if os.path.exists(path): + print("Loading global CloudHarness config at", path) +@@ -34,11 +35,11 @@ def _load_config(): + values = yaml.safe_load(f) + cfg = _merge_dictionaries(cfg, values) + cfg['root'] = values +- ++ # EDIT: CLOUDHARNESS END + return cfg + + +-@lru_cache() ++@lru_cache + def _get_config_value(key): + """Load value from the k8s ConfigMap given a key.""" + +@@ -50,7 +51,7 @@ def _get_config_value(key): + raise Exception(f"{path} not found!") + + +-@lru_cache() ++@lru_cache + def get_secret_value(key, default="never-explicitly-set"): + """Load value from the user managed k8s Secret or the default k8s Secret + given a key.""" +@@ -117,7 +118,7 @@ def get_config(key, default=None): + else: + value = value[level] + +- ++ # EDIT: CLOUDHARNESS START + if value and isinstance(value, str): + replace_var = re.search("{{.*?}}", value) + if replace_var: +@@ -128,6 +129,7 @@ def get_config(key, default=None): + if repl: + print("replace", variable, "in", value, ":", repl) + value = re.sub("{{.*?}}", repl, value) ++ # EDIT: CLOUDHARNESS END + return value + + +@@ -137,6 +139,5 @@ def set_config_if_not_none(cparent, name, key): + configuration item if not None + """ + data = get_config(key) +- + if data is not None: +- setattr(cparent, name, data) +\ No newline at end of file ++ setattr(cparent, name, data) +diff --git a/applications/jupyterhub/deploy/templates/NOTES.txt b/applications/jupyterhub/deploy/templates/NOTES.txt +new file mode 100644 +index 0000000..9769a9c +--- /dev/null ++++ b/applications/jupyterhub/deploy/templates/NOTES.txt +@@ -0,0 +1,158 @@ ++{{- $proxy_service := include "jupyterhub.proxy-public.fullname" . -}} ++ ++{{- /* Generated with https://patorjk.com/software/taag/#p=display&h=0&f=Slant&t=JupyterHub */}} ++. __ __ __ __ __ ++ / / __ __ ____ __ __ / /_ ___ _____ / / / / __ __ / /_ ++ __ / / / / / / / __ \ / / / / / __/ / _ \ / ___/ / /_/ / / / / / / __ \ ++/ /_/ / / /_/ / / /_/ / / /_/ / / /_ / __/ / / / __ / / /_/ / / /_/ / ++\____/ \__,_/ / .___/ \__, / \__/ \___/ /_/ /_/ /_/ \__,_/ /_.___/ ++ /_/ /____/ ++ ++ You have successfully installed the official JupyterHub Helm chart! ++ ++### Installation info ++ ++ - Kubernetes namespace: {{ .Release.Namespace }} ++ - Helm release name: {{ .Release.Name }} ++ - Helm chart version: {{ .Chart.Version }} ++ - JupyterHub version: {{ .Chart.AppVersion }} ++ - Hub pod packages: See https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/{{ include "jupyterhub.chart-version-to-git-ref" .Chart.Version }}/images/hub/requirements.txt ++ ++### Followup links ++ ++ - Documentation: https://z2jh.jupyter.org ++ - Help forum: https://discourse.jupyter.org ++ - Social chat: https://gitter.im/jupyterhub/jupyterhub ++ - Issue tracking: https://github.com/jupyterhub/zero-to-jupyterhub-k8s/issues ++ ++### Post-installation checklist ++ ++ - Verify that created Pods enter a Running state: ++ ++ kubectl --namespace={{ .Release.Namespace }} get pod ++ ++ If a pod is stuck with a Pending or ContainerCreating status, diagnose with: ++ ++ kubectl --namespace={{ .Release.Namespace }} describe pod ++ ++ If a pod keeps restarting, diagnose with: ++ ++ kubectl --namespace={{ .Release.Namespace }} logs --previous ++ {{- println }} ++ ++ {{- if eq .Values.apps.jupyterhub.proxy.service.type "LoadBalancer" }} ++ - Verify an external IP is provided for the k8s Service {{ $proxy_service }}. ++ ++ kubectl --namespace={{ .Release.Namespace }} get service {{ $proxy_service }} ++ ++ If the external ip remains , diagnose with: ++ ++ kubectl --namespace={{ .Release.Namespace }} describe service {{ $proxy_service }} ++ {{- end }} ++ ++ - Verify web based access: ++ {{- println }} ++ {{- if .Values.apps.jupyterhub.ingress.enabled }} ++ {{- range $host := .Values.apps.jupyterhub.ingress.hosts }} ++ Try insecure HTTP access: http://{{ $host }}{{ $.Values.apps.jupyterhub.hub.baseUrl | trimSuffix "/" }}/ ++ {{- end }} ++ ++ {{- range $tls := .Values.apps.jupyterhub.ingress.tls }} ++ {{- range $host := $tls.hosts }} ++ Try secure HTTPS access: https://{{ $host }}{{ $.Values.apps.jupyterhub.hub.baseUrl | trimSuffix "/" }}/ ++ {{- end }} ++ {{- end }} ++ {{- else }} ++ You have not configured a k8s Ingress resource so you need to access the k8s ++ Service {{ $proxy_service }} directly. ++ {{- println }} ++ ++ {{- if eq .Values.apps.jupyterhub.proxy.service.type "NodePort" }} ++ The k8s Service {{ $proxy_service }} is exposed via NodePorts. That means ++ that all the k8s cluster's nodes are exposing the k8s Service via those ++ ports. ++ ++ Try insecure HTTP access: http://:{{ .Values.apps.jupyterhub.proxy.service.nodePorts.http | default "no-http-nodeport-set"}} ++ Try secure HTTPS access: https://:{{ .Values.apps.jupyterhub.proxy.service.nodePorts.https | default "no-https-nodeport-set" }} ++ ++ {{- else }} ++ If your computer is outside the k8s cluster, you can port-forward traffic to ++ the k8s Service {{ $proxy_service }} with kubectl to access it from your ++ computer. ++ ++ kubectl --namespace={{ .Release.Namespace }} port-forward service/{{ $proxy_service }} 8080:http ++ ++ Try insecure HTTP access: http://localhost:8080 ++ {{- end }} ++ {{- end }} ++ {{- println }} ++ ++ ++ ++ ++ ++{{- /* ++ Warnings for likely misconfigurations ++*/}} ++ ++{{- if and (not .Values.apps.jupyterhub.scheduling.podPriority.enabled) (and .Values.apps.jupyterhub.scheduling.userPlaceholder.enabled .Values.apps.jupyterhub.scheduling.userPlaceholder.replicas) }} ++################################################################################# ++###### WARNING: You are using user placeholders without pod priority ##### ++###### enabled*, either enable pod priority or stop using the ##### ++###### user placeholders** to avoid having placeholders that ##### ++###### refuse to make room for a real user. ##### ++###### ##### ++###### *scheduling.podPriority.enabled ##### ++###### **scheduling.userPlaceholder.enabled ##### ++###### **scheduling.userPlaceholder.replicas ##### ++################################################################################# ++{{- println }} ++{{- end }} ++ ++ ++ ++ ++ ++{{- /* ++ Breaking changes and failures for likely misconfigurations. ++*/}} ++ ++{{- $breaking := "" }} ++{{- $breaking_title := "\n" }} ++{{- $breaking_title = print $breaking_title "\n#################################################################################" }} ++{{- $breaking_title = print $breaking_title "\n###### BREAKING: The config values passed contained no longer accepted #####" }} ++{{- $breaking_title = print $breaking_title "\n###### options. See the messages below for more details. #####" }} ++{{- $breaking_title = print $breaking_title "\n###### #####" }} ++{{- $breaking_title = print $breaking_title "\n###### To verify your updated config is accepted, you can use #####" }} ++{{- $breaking_title = print $breaking_title "\n###### the `helm template` command. #####" }} ++{{- $breaking_title = print $breaking_title "\n#################################################################################" }} ++ ++ ++{{- /* ++ This is an example (in a helm template comment) on how to detect and ++ communicate with regards to a breaking chart config change. ++ ++ {{- if hasKey .Values.apps.jupyterhub.singleuser.cloudMetadata "enabled" }} ++ {{- $breaking = print $breaking "\n\nCHANGED: singleuser.cloudMetadata.enabled must as of 1.0.0 be configured using singleuser.cloudMetadata.blockWithIptables with the opposite value." }} ++ {{- end }} ++*/}} ++ ++ ++{{- if hasKey .Values.apps.jupyterhub.rbac "enabled" }} ++{{- $breaking = print $breaking "\n\nCHANGED: rbac.enabled must as of version 2.0.0 be configured via rbac.create and .serviceAccount.create." }} ++{{- end }} ++ ++ ++{{- if hasKey .Values.apps.jupyterhub.hub "fsGid" }} ++{{- $breaking = print $breaking "\n\nCHANGED: hub.fsGid must as of version 2.0.0 be configured via hub.podSecurityContext.fsGroup." }} ++{{- end }} ++ ++ ++{{- if and .Values.apps.jupyterhub.singleuser.cloudMetadata.blockWithIptables (and .Values.apps.jupyterhub.singleuser.networkPolicy.enabled .Values.apps.jupyterhub.singleuser.networkPolicy.egressAllowRules.cloudMetadataServer) }} ++{{- $breaking = print $breaking "\n\nCHANGED: singleuser.cloudMetadata.blockWithIptables must as of version 3.0.0 not be configured together with singleuser.networkPolicy.egressAllowRules.cloudMetadataServer as it leads to an ambiguous configuration." }} ++{{- end }} ++ ++ ++{{- if $breaking }} ++{{- fail (print $breaking_title $breaking "\n\n") }} ++{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl b/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl +index b742a12..3159d10 100644 +--- a/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl ++++ b/applications/jupyterhub/deploy/templates/_helpers-auth-rework.tpl +@@ -168,30 +168,30 @@ ldap.dn.user.useLookupName: LDAPAuthenticator.use_lookup_dn_username + {{- $c := dict }} + {{- $result := (dict "hub" (dict "config" $c)) }} + {{- /* +- Flattens the config in .Values.apps.jupyterhub.auth to a format of ++ Flattens the config in .Values.apps.jupyterhub.apps.jupyterhub.auth to a format of + "keyX.keyY...": "value". Writes output to $c. + */}} +- {{- include "jupyterhub.flattenDict" (list $c (omit .Values.apps.jupyterhub.auth "type" "custom")) }} ++ {{- include "jupyterhub.flattenDict" (list $c (omit .Values.apps.jupyterhub.apps.jupyterhub.auth "type" "custom")) }} + + {{- /* + Transform the flattened config using a dictionary + representing the old z2jh config, output the result + in $c. + */}} +- {{- include "jupyterhub.authDep.remapOldToNew.mappable" (list $c .Values.apps.jupyterhub.global.safeToShowValues) }} ++ {{- include "jupyterhub.authDep.remapOldToNew.mappable" (list $c .Values.apps.jupyterhub.apps.jupyterhub.global.safeToSho.Values.apps.jupyterhub. }} + +- {{- $class_old_config_key := .Values.apps.jupyterhub.auth.type | default "" }} {{- /* ldap - github */}} ++ {{- $class_old_config_key := .Values.apps.jupyterhub.apps.jupyterhub.auth.type | default "" }} {{- /* ldap - github */}} + {{- $class_new_entrypoint := "" }} {{- /* ldapauthenticator.LDAPAuthenticator - github */}} + {{- $class_new_config_key := "" }} {{- /* LDAPAuthenticator - GitHubOAuthenticator */}} + + {{- /* SET $class_new_entrypoint, $class_new_config_key */}} + {{- if eq $class_old_config_key "custom" }} +- {{- $class_new_entrypoint = .Values.apps.jupyterhub.auth.custom.className | default "custom.className wasn't configured!" }} ++ {{- $class_new_entrypoint = .Values.apps.jupyterhub.apps.jupyterhub.auth.custom.className | default "custom.className wasn't configured!" }} + {{- $class_new_config_key = $class_new_entrypoint | splitList "." | last }} + {{- /* UPDATE c dict explicitly with auth.custom.config */}} +- {{- if .Values.apps.jupyterhub.auth.custom.config }} +- {{- $custom_config := merge (dict) .Values.apps.jupyterhub.auth.custom.config }} +- {{- if not .Values.apps.jupyterhub.global.safeToShowValues }} ++ {{- if .Values.apps.jupyterhub.apps.jupyterhub.auth.custom.config }} ++ {{- $custom_config := merge (dict) .Values.apps.jupyterhub.apps.jupyterhub.auth.custom.config }} ++ {{- if not .Values.apps.jupyterhub.apps.jupyterhub.global.safeToSho.Values.apps.jupyterhub.}} + {{- range $key, $val := $custom_config }} + {{- $_ := set $custom_config $key "***" }} + {{- end }} +@@ -213,7 +213,7 @@ The JupyterHub Helm chart's auth config has been reworked and requires changes. + + The new way to configure authentication in chart version 0.11.0+ is printed + below for your convenience. The values are not shown by default to ensure no +-secrets are exposed, run helm upgrade with --set global.safeToShowValues=true ++secrets are exposed, run helm upgrade with --set global.safeToSho.Values.apps.jupyterhub.true + to show them. + + {{ $result | toYaml }} +diff --git a/applications/jupyterhub/deploy/templates/_helpers-names.tpl b/applications/jupyterhub/deploy/templates/_helpers-names.tpl +index e9cf7bb..401d601 100644 +--- a/applications/jupyterhub/deploy/templates/_helpers-names.tpl ++++ b/applications/jupyterhub/deploy/templates/_helpers-names.tpl +@@ -3,8 +3,8 @@ + parent charts to reference these dynamic resource names. + + To avoid duplicating documentation, for more information, please see the the +- fullnameOverride entry in schema.yaml or the configuration reference that +- schema.yaml renders to. ++ fullnameOverride entry in values.schema.yaml or the configuration reference ++ that values.schema.yaml renders to. + + https://z2jh.jupyter.org/en/latest/resources/reference.html#fullnameOverride + */}} +@@ -38,8 +38,8 @@ + {{- $name_override := .Values.apps.jupyterhub.nameOverride }} + {{- if ne .Chart.Name "jupyterhub" }} + {{- if .Values.apps.jupyterhub.jupyterhub }} +- {{- $fullname_override = .Values.apps.jupyterhub.fullnameOverride }} +- {{- $name_override = .Values.apps.jupyterhub.nameOverride }} ++ {{- $fullname_override = .Values.apps.jupyterhub.jupyterhub.fullnameOverride }} ++ {{- $name_override = .Values.apps.jupyterhub.jupyterhub.nameOverride }} + {{- end }} + {{- end }} + +@@ -76,12 +76,23 @@ + {{- include "jupyterhub.fullname.dash" . }}hub + {{- end }} + ++{{- /* hub-serviceaccount ServiceAccount */}} ++{{- define "jupyterhub.hub-serviceaccount.fullname" -}} ++ {{- if .Values.apps.jupyterhub.hub.serviceAccount.create }} ++ {{- .Values.apps.jupyterhub.hub.serviceAccount.name | default (include "jupyterhub.hub.fullname" .) }} ++ {{- else }} ++ {{- .Values.apps.jupyterhub.hub.serviceAccount.name | default "default" }} ++ {{- end }} ++{{- end }} ++ + {{- /* hub-existing-secret Secret */}} + {{- define "jupyterhub.hub-existing-secret.fullname" -}} + {{- /* A hack to avoid issues from invoking this from a parent Helm chart. */}} + {{- $existing_secret := .Values.apps.jupyterhub.hub.existingSecret }} + {{- if ne .Chart.Name "jupyterhub" }} +- {{- $existing_secret = .Values.apps.jupyterhub.hub.existingSecret }} ++ {{- if .Values.apps.jupyterhub.jupyterhub }} ++ {{- $existing_secret = .Values.apps.jupyterhub.jupyterhub.hub.existingSecret }} ++ {{- end }} + {{- end }} + {{- if $existing_secret }} + {{- $existing_secret }} +@@ -133,11 +144,29 @@ + {{- include "jupyterhub.fullname.dash" . }}autohttps + {{- end }} + ++{{- /* autohttps-serviceaccount ServiceAccount */}} ++{{- define "jupyterhub.autohttps-serviceaccount.fullname" -}} ++ {{- if .Values.apps.jupyterhub.proxy.traefik.serviceAccount.create }} ++ {{- .Values.apps.jupyterhub.proxy.traefik.serviceAccount.name | default (include "jupyterhub.autohttps.fullname" .) }} ++ {{- else }} ++ {{- .Values.apps.jupyterhub.proxy.traefik.serviceAccount.name | default "default" }} ++ {{- end }} ++{{- end }} ++ + {{- /* user-scheduler Deployment */}} + {{- define "jupyterhub.user-scheduler-deploy.fullname" -}} + {{- include "jupyterhub.fullname.dash" . }}user-scheduler + {{- end }} + ++{{- /* user-scheduler-serviceaccount ServiceAccount */}} ++{{- define "jupyterhub.user-scheduler-serviceaccount.fullname" -}} ++ {{- if .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.create }} ++ {{- .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.name | default (include "jupyterhub.user-scheduler-deploy.fullname" .) }} ++ {{- else }} ++ {{- .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.name | default "default" }} ++ {{- end }} ++{{- end }} ++ + {{- /* user-scheduler leader election lock resource */}} + {{- define "jupyterhub.user-scheduler-lock.fullname" -}} + {{- include "jupyterhub.user-scheduler-deploy.fullname" . }}-lock +@@ -153,6 +182,15 @@ + {{- include "jupyterhub.fullname.dash" . }}hook-image-awaiter + {{- end }} + ++{{- /* image-awaiter-serviceaccount ServiceAccount */}} ++{{- define "jupyterhub.hook-image-awaiter-serviceaccount.fullname" -}} ++ {{- if .Values.apps.jupyterhub.prePuller.hook.serviceAccount.create }} ++ {{- .Values.apps.jupyterhub.prePuller.hook.serviceAccount.name | default (include "jupyterhub.hook-image-awaiter.fullname" .) }} ++ {{- else }} ++ {{- .Values.apps.jupyterhub.prePuller.hook.serviceAccount.name | default "default" }} ++ {{- end }} ++{{- end }} ++ + {{- /* hook-image-puller DaemonSet */}} + {{- define "jupyterhub.hook-image-puller.fullname" -}} + {{- include "jupyterhub.fullname.dash" . }}hook-image-puller +@@ -210,6 +248,15 @@ + {{- end }} + {{- end }} + ++{{- /* image-puller Priority */}} ++{{- define "jupyterhub.image-puller-priority.fullname" -}} ++ {{- if (include "jupyterhub.fullname" .) }} ++ {{- include "jupyterhub.fullname.dash" . }}image-puller ++ {{- else }} ++ {{- .Release.Name }}-image-puller-priority ++ {{- end }} ++{{- end }} ++ + {{- /* user-scheduler's registered name */}} + {{- define "jupyterhub.user-scheduler.fullname" -}} + {{- if (include "jupyterhub.fullname" .) }} +@@ -231,6 +278,7 @@ + fullname: {{ include "jupyterhub.fullname" . | quote }} + fullname-dash: {{ include "jupyterhub.fullname.dash" . | quote }} + hub: {{ include "jupyterhub.hub.fullname" . | quote }} ++hub-serviceaccount: {{ include "jupyterhub.hub-serviceaccount.fullname" . | quote }} + hub-existing-secret: {{ include "jupyterhub.hub-existing-secret.fullname" . | quote }} + hub-existing-secret-or-default: {{ include "jupyterhub.hub-existing-secret-or-default.fullname" . | quote }} + hub-pvc: {{ include "jupyterhub.hub-pvc.fullname" . | quote }} +@@ -241,10 +289,14 @@ proxy-public: {{ include "jupyterhub.proxy-public.fullname" . | quote }} + proxy-public-tls: {{ include "jupyterhub.proxy-public-tls.fullname" . | quote }} + proxy-public-manual-tls: {{ include "jupyterhub.proxy-public-manual-tls.fullname" . | quote }} + autohttps: {{ include "jupyterhub.autohttps.fullname" . | quote }} ++autohttps-serviceaccount: {{ include "jupyterhub.autohttps-serviceaccount.fullname" . | quote }} + user-scheduler-deploy: {{ include "jupyterhub.user-scheduler-deploy.fullname" . | quote }} ++user-scheduler-serviceaccount: {{ include "jupyterhub.user-scheduler-serviceaccount.fullname" . | quote }} + user-scheduler-lock: {{ include "jupyterhub.user-scheduler-lock.fullname" . | quote }} + user-placeholder: {{ include "jupyterhub.user-placeholder.fullname" . | quote }} ++image-puller-priority: {{ include "jupyterhub.image-puller-priority.fullname" . | quote }} + hook-image-awaiter: {{ include "jupyterhub.hook-image-awaiter.fullname" . | quote }} ++hook-image-awaiter-serviceaccount: {{ include "jupyterhub.hook-image-awaiter-serviceaccount.fullname" . | quote }} + hook-image-puller: {{ include "jupyterhub.hook-image-puller.fullname" . | quote }} + continuous-image-puller: {{ include "jupyterhub.continuous-image-puller.fullname" . | quote }} + singleuser: {{ include "jupyterhub.singleuser.fullname" . | quote }} +diff --git a/applications/jupyterhub/deploy/templates/_helpers-netpol.tpl b/applications/jupyterhub/deploy/templates/_helpers-netpol.tpl +new file mode 100644 +index 0000000..4075569 +--- /dev/null ++++ b/applications/jupyterhub/deploy/templates/_helpers-netpol.tpl +@@ -0,0 +1,101 @@ ++{{- /* ++ This named template renders egress rules for NetworkPolicy resources based on ++ common configuration. ++ ++ It is rendering based on the `egressAllowRules` and `egress` keys of the ++ passed networkPolicy config object. Each flag set to true under ++ `egressAllowRules` is rendered to a egress rule that next to any custom user ++ defined rules from the `egress` config. ++ ++ This named template needs to render based on a specific networkPolicy ++ resource, but also needs access to the root context. Due to that, it ++ accepts a list as its scope, where the first element is supposed to be the ++ root context and the second element is supposed to be the networkPolicy ++ configuration object. ++ ++ As an example, this is how you would render this named template from a ++ NetworkPolicy resource under its egress: ++ ++ egress: ++ # other rules here... ++ ++ {{- with (include "jupyterhub.networkPolicy.renderEgressRules" (list . .Values.apps.jupyterhub.hub.networkPolicy)) }} ++ {{- . | nindent 4 }} ++ {{- end }} ++ ++ Note that the reference to privateIPs and nonPrivateIPs relate to ++ https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses. ++*/}} ++ ++{{- define "jupyterhub.networkPolicy.renderEgressRules" -}} ++{{- $root := index . 0 }} ++{{- $netpol := index . 1 }} ++{{- if or (or $netpol.egressAllowRules.dnsPortsCloudMetadataServer $netpol.egressAllowRules.dnsPortsKubeSystemNamespace) $netpol.egressAllowRules.dnsPortsPrivateIPs }} ++- ports: ++ - port: 53 ++ protocol: UDP ++ - port: 53 ++ protocol: TCP ++ to: ++ {{- if $netpol.egressAllowRules.dnsPortsCloudMetadataServer }} ++ # Allow outbound connections to DNS ports on the cloud metadata server ++ - ipBlock: ++ cidr: {{ $root.Values.apps.jupyterhub.singleuser.cloudMetadata.ip }}/32 ++ {{- end }} ++ {{- if $netpol.egressAllowRules.dnsPortsKubeSystemNamespace }} ++ # Allow outbound connections to DNS ports on pods in the kube-system ++ # namespace ++ - namespaceSelector: ++ matchLabels: ++ kubernetes.io/metadata.name: kube-system ++ {{- end }} ++ {{- if $netpol.egressAllowRules.dnsPortsPrivateIPs }} ++ # Allow outbound connections to DNS ports on destinations in the private IP ++ # ranges ++ - ipBlock: ++ cidr: 10.0.0.0/8 ++ - ipBlock: ++ cidr: 172.16.0.0/12 ++ - ipBlock: ++ cidr: 192.168.0.0/16 ++ {{- end }} ++{{- end }} ++ ++{{- if $netpol.egressAllowRules.nonPrivateIPs }} ++# Allow outbound connections to non-private IP ranges ++- to: ++ - ipBlock: ++ cidr: 0.0.0.0/0 ++ except: ++ # As part of this rule: ++ # - don't allow outbound connections to private IPs ++ - 10.0.0.0/8 ++ - 172.16.0.0/12 ++ - 192.168.0.0/16 ++ # - don't allow outbound connections to the cloud metadata server ++ - {{ $root.Values.apps.jupyterhub.singleuser.cloudMetadata.ip }}/32 ++{{- end }} ++ ++{{- if $netpol.egressAllowRules.privateIPs }} ++# Allow outbound connections to private IP ranges ++- to: ++ - ipBlock: ++ cidr: 10.0.0.0/8 ++ - ipBlock: ++ cidr: 172.16.0.0/12 ++ - ipBlock: ++ cidr: 192.168.0.0/16 ++{{- end }} ++ ++{{- if $netpol.egressAllowRules.cloudMetadataServer }} ++# Allow outbound connections to the cloud metadata server ++- to: ++ - ipBlock: ++ cidr: {{ $root.Values.apps.jupyterhub.singleuser.cloudMetadata.ip }}/32 ++{{- end }} ++ ++{{- with $netpol.egress }} ++# Allow outbound connections based on user specified rules ++{{ . | toYaml }} ++{{- end }} ++{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/_helpers.tpl b/applications/jupyterhub/deploy/templates/_helpers.tpl +index efea86d..a202363 100755 +--- a/applications/jupyterhub/deploy/templates/_helpers.tpl ++++ b/applications/jupyterhub/deploy/templates/_helpers.tpl +@@ -12,7 +12,7 @@ + + When you ask a helper to render its content, one often forward the current + scope to the helper in order to allow it to access .Release.Name, +- .Values.apps.jupyterhub.rbac.enabled and similar values. ++ .Values.apps.jupyterhub.rbac.create and similar values. + + #### Example - Passing the current scope + {{ include "jupyterhub.commonLabels" . }} +@@ -180,8 +180,51 @@ component: {{ include "jupyterhub.componentLabel" . }} + Augments passed .pullSecrets with $.Values.apps.jupyterhub.imagePullSecrets + */}} + {{- define "jupyterhub.imagePullSecrets" -}} ++ {{- /* ++ We have implemented a trick to allow a parent chart depending on this ++ chart to call this named templates. ++ ++ Caveats and notes: ++ ++ 1. While parent charts can reference these, grandparent charts can't. ++ 2. Parent charts must not use an alias for this chart. ++ 3. There is no failsafe workaround to above due to ++ https://github.com/helm/helm/issues/9214. ++ 4. .Chart is of its own type (*chart.Metadata) and needs to be casted ++ using "toYaml | fromYaml" in order to be able to use normal helm ++ template functions on it. ++ */}} ++ {{- $jupyterhub_values := .root.Values.apps.jupyterhub.}} ++ {{- if ne .root.Chart.Name "jupyterhub" }} ++ {{- if .root.Values.apps.jupyterhub.jupyterhub }} ++ {{- $jupyterhub_values = .root.Values.apps.jupyterhub.jupyterhub }} ++ {{- end }} ++ {{- end }} + ++ {{- /* Populate $_.list with all relevant entries */}} ++ {{- $_ := dict "list" (concat .image.pullSecrets $jupyterhub_values.imagePullSecrets | uniq) }} ++ {{- if and $jupyterhub_values.imagePullSecret.create $jupyterhub_values.imagePullSecret.automaticReferenceInjection }} ++ {{- $__ := set $_ "list" (append $_.list (include "jupyterhub.image-pull-secret.fullname" .root) | uniq) }} ++ {{- end }} + ++ {{- /* Decide if something should be written */}} ++ {{- if not (eq ($_.list | toJson) "[]") }} ++ ++ {{- /* Process the $_.list where strings become dicts with a name key and the ++ strings become the name keys' values into $_.res */}} ++ {{- $_ := set $_ "res" list }} ++ {{- range $_.list }} ++ {{- if eq (typeOf .) "string" }} ++ {{- $__ := set $_ "res" (append $_.res (dict "name" .)) }} ++ {{- else }} ++ {{- $__ := set $_ "res" (append $_.res .) }} ++ {{- end }} ++ {{- end }} ++ ++ {{- /* Write the results */}} ++ {{- $_.res | toJson }} ++ ++ {{- end }} + {{- end }} + + {{- /* +@@ -339,3 +382,21 @@ limits: + {{- print "\n\nextraFiles entries (" $file_key ") must only contain one of the fields: 'data', 'stringData', and 'binaryData'." | fail }} + {{- end }} + {{- end }} ++ ++{{- /* ++ jupyterhub.chart-version-to-git-ref: ++ Renders a valid git reference from a chartpress generated version string. ++ In practice, either a git tag or a git commit hash will be returned. ++ ++ - The version string will follow a chartpress pattern, see ++ https://github.com/jupyterhub/chartpress#examples-chart-versions-and-image-tags. ++ ++ - The regexReplaceAll function is a sprig library function, see ++ https://masterminds.github.io/sprig/strings.html. ++ ++ - The regular expression is in golang syntax, but \d had to become \\d for ++ example. ++*/}} ++{{- define "jupyterhub.chart-version-to-git-ref" -}} ++{{- regexReplaceAll ".*[.-]n\\d+[.]h(.*)" . "${1}" }} ++{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/hub/configmap.yaml b/applications/jupyterhub/deploy/templates/hub/configmap.yaml +index c913f67..f52feb6 100755 +--- a/applications/jupyterhub/deploy/templates/hub/configmap.yaml ++++ b/applications/jupyterhub/deploy/templates/hub/configmap.yaml +@@ -29,5 +29,6 @@ data: + */}} + checksum_hook-image-puller: {{ include "jupyterhub.imagePuller.daemonset.hook.checksum" . | quote }} + ++ # EDIT: CLOUDHARNESS + allvalues.yaml: | + {{- .Values | toYaml | nindent 4 }} +\ No newline at end of file +diff --git a/applications/jupyterhub/deploy/templates/hub/deployment.yaml b/applications/jupyterhub/deploy/templates/hub/deployment.yaml +index 82132c6..d105ecc 100755 +--- a/applications/jupyterhub/deploy/templates/hub/deployment.yaml ++++ b/applications/jupyterhub/deploy/templates/hub/deployment.yaml +@@ -5,6 +5,9 @@ metadata: + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} + spec: ++ {{- if typeIs "int" .Values.apps.jupyterhub.hub.revisionHistoryLimit }} ++ revisionHistoryLimit: {{ .Values.apps.jupyterhub.hub.revisionHistoryLimit }} ++ {{- end }} + replicas: 1 + selector: + matchLabels: +@@ -30,11 +33,14 @@ spec: + {{- . | toYaml | nindent 8 }} + {{- end }} + spec: +-{{ include "deploy_utils.etcHosts" . | indent 6 }} ++{{ include "deploy_utils.etcHosts" . | indent 6 }} # EDIT: CLOUDHARNESS + {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} + priorityClassName: {{ include "jupyterhub.priority.fullname" . }} + {{- end }} +- nodeSelector: {{ toJson .Values.apps.jupyterhub.hub.nodeSelector }} ++ {{- with .Values.apps.jupyterhub.hub.nodeSelector }} ++ nodeSelector: ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.hub.tolerations }} + tolerations: + {{- . | toYaml | nindent 8 }} +@@ -44,7 +50,7 @@ spec: + - name: config + configMap: + name: {{ include "jupyterhub.hub.fullname" . }} +- {{- /* This is needed by cloudharness libraries */}} ++ {{- /* EDIT: CLOUDHARNESS This is needed by cloudharness libraries */}} + - name: cloudharness-allvalues + configMap: + name: cloudharness-allvalues +@@ -82,11 +88,13 @@ spec: + persistentVolumeClaim: + claimName: {{ include "jupyterhub.hub-pvc.fullname" . }} + {{- end }} +- {{- if .Values.apps.jupyterhub.rbac.enabled }} +- serviceAccountName: {{ include "jupyterhub.hub.fullname" . }} ++ {{- with include "jupyterhub.hub-serviceaccount.fullname" . }} ++ serviceAccountName: {{ . }} + {{- end }} ++ {{- with .Values.apps.jupyterhub.hub.podSecurityContext }} + securityContext: +- fsGroup: {{ .Values.apps.jupyterhub.hub.fsGid }} ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + {{- with include "jupyterhub.imagePullSecrets" (dict "root" . "image" .Values.apps.jupyterhub.hub.image) }} + imagePullSecrets: {{ . }} + {{- end }} +@@ -153,14 +161,14 @@ spec: + name: config + - mountPath: /usr/local/etc/jupyterhub/secret/ + name: secret +- - name: cloudharness-allvalues ++ - name: cloudharness-allvalues # EDIT: CLOUDHARNESS START + mountPath: /opt/cloudharness/resources/allvalues.yaml + subPath: allvalues.yaml + {{- if .Values.apps.accounts }} + - name: cloudharness-kc-accounts + mountPath: /opt/cloudharness/resources/auth + readOnly: true +- {{- end }} ++ {{- end }} # EDIT: CLOUDHARNESS END + {{- if (include "jupyterhub.hub-existing-secret.fullname" .) }} + - mountPath: /usr/local/etc/jupyterhub/existing-secret/ + name: existing-secret +diff --git a/applications/jupyterhub/deploy/templates/hub/netpol.yaml b/applications/jupyterhub/deploy/templates/hub/netpol.yaml +index 9a7a6bc..d9508e2 100755 +--- a/applications/jupyterhub/deploy/templates/hub/netpol.yaml ++++ b/applications/jupyterhub/deploy/templates/hub/netpol.yaml +@@ -61,31 +61,24 @@ spec: + + egress: + # hub --> proxy +- - ports: +- - port: 8001 +- to: ++ - to: + - podSelector: + matchLabels: + {{- $_ := merge (dict "componentLabel" "proxy") . }} + {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} ++ ports: ++ - port: 8001 ++ + # hub --> singleuser-server +- - ports: +- - port: 8888 +- to: ++ - to: + - podSelector: + matchLabels: + {{- $_ := merge (dict "componentLabel" "singleuser-server") . }} + {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} ++ ports: ++ - port: 8888 + +- # hub --> Kubernetes internal DNS +- - ports: +- - protocol: UDP +- port: 53 +- - protocol: TCP +- port: 53 +- +- {{- with .Values.apps.jupyterhub.hub.networkPolicy.egress }} +- # hub --> depends, but the default is everything +- {{- . | toYaml | nindent 4 }} ++ {{- with (include "jupyterhub.networkPolicy.renderEgressRules" (list . .Values.apps.jupyterhub.hub.networkPolicy)) }} ++ {{- . | nindent 4 }} + {{- end }} + {{- end }} +diff --git a/applications/jupyterhub/deploy/templates/hub/pdb.yaml b/applications/jupyterhub/deploy/templates/hub/pdb.yaml +index 855609d..bb6c7b1 100755 +--- a/applications/jupyterhub/deploy/templates/hub/pdb.yaml ++++ b/applications/jupyterhub/deploy/templates/hub/pdb.yaml +@@ -1,9 +1,5 @@ + {{- if .Values.apps.jupyterhub.hub.pdb.enabled -}} +-{{- if .Capabilities.APIVersions.Has "policy/v1" }} + apiVersion: policy/v1 +-{{- else }} +-apiVersion: policy/v1beta1 +-{{- end }} + kind: PodDisruptionBudget + metadata: + name: {{ include "jupyterhub.hub.fullname" . }} +diff --git a/applications/jupyterhub/deploy/templates/hub/rbac.yaml b/applications/jupyterhub/deploy/templates/hub/rbac.yaml +index 738daab..1b689af 100755 +--- a/applications/jupyterhub/deploy/templates/hub/rbac.yaml ++++ b/applications/jupyterhub/deploy/templates/hub/rbac.yaml +@@ -1,15 +1,4 @@ +-{{- if .Values.apps.jupyterhub.rbac.enabled -}} +-apiVersion: v1 +-kind: ServiceAccount +-metadata: +- name: {{ include "jupyterhub.hub.fullname" . }} +- {{- with .Values.apps.jupyterhub.hub.serviceAccount.annotations }} +- annotations: +- {{- . | toYaml | nindent 4 }} +- {{- end }} +- labels: +- {{- include "jupyterhub.labels" . | nindent 4 }} +---- ++{{- if .Values.apps.jupyterhub.rbac.create -}} + kind: Role + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +@@ -32,7 +21,7 @@ metadata: + {{- include "jupyterhub.labels" . | nindent 4 }} + subjects: + - kind: ServiceAccount +- name: {{ include "jupyterhub.hub.fullname" . }} ++ name: {{ include "jupyterhub.hub-serviceaccount.fullname" . }} + namespace: "{{ .Release.Namespace }}" + roleRef: + kind: Role +diff --git a/applications/jupyterhub/deploy/templates/hub/serviceaccount.yaml b/applications/jupyterhub/deploy/templates/hub/serviceaccount.yaml +new file mode 100644 +index 0000000..817ed66 +--- /dev/null ++++ b/applications/jupyterhub/deploy/templates/hub/serviceaccount.yaml +@@ -0,0 +1,12 @@ ++{{- if .Values.apps.jupyterhub.hub.serviceAccount.create -}} ++apiVersion: v1 ++kind: ServiceAccount ++metadata: ++ name: {{ include "jupyterhub.hub-serviceaccount.fullname" . }} ++ {{- with .Values.apps.jupyterhub.hub.serviceAccount.annotations }} ++ annotations: ++ {{- . | toYaml | nindent 4 }} ++ {{- end }} ++ labels: ++ {{- include "jupyterhub.labels" . | nindent 4 }} ++{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/image-pull-secret.yaml b/applications/jupyterhub/deploy/templates/image-pull-secret.yaml +new file mode 100644 +index 0000000..b7544db +--- /dev/null ++++ b/applications/jupyterhub/deploy/templates/image-pull-secret.yaml +@@ -0,0 +1,15 @@ ++{{- if .Values.apps.jupyterhub.imagePullSecret.create }} ++kind: Secret ++apiVersion: v1 ++metadata: ++ name: {{ include "jupyterhub.image-pull-secret.fullname" . }} ++ labels: ++ {{- include "jupyterhub.labels" . | nindent 4 }} ++ annotations: ++ "helm.sh/hook": pre-install,pre-upgrade ++ "helm.sh/hook-delete-policy": before-hook-creation ++ "helm.sh/hook-weight": "-20" ++type: kubernetes.io/dockerconfigjson ++data: ++ .dockerconfigjson: {{ include "jupyterhub.dockerconfigjson" . }} ++{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl b/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl +index e16fd1a..528345c 100644 +--- a/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl ++++ b/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl +@@ -34,6 +34,9 @@ spec: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 100% ++ {{- if typeIs "int" .Values.apps.jupyterhub.prePuller.revisionHistoryLimit }} ++ revisionHistoryLimit: {{ .Values.apps.jupyterhub.prePuller.revisionHistoryLimit }} ++ {{- end }} + template: + metadata: + labels: +@@ -44,13 +47,17 @@ spec: + {{- end }} + spec: + {{- /* +- continuous-image-puller pods are made evictable to save on the k8s pods +- per node limit all k8s clusters have. ++ image-puller pods are made evictable to save on the k8s pods ++ per node limit all k8s clusters have and have a higher priority ++ than user-placeholder pods that could block an entire node. + */}} +- {{- if and (not .hook) .Values.apps.jupyterhub.scheduling.podPriority.enabled }} +- priorityClassName: {{ include "jupyterhub.user-placeholder-priority.fullname" . }} ++ {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} ++ priorityClassName: {{ include "jupyterhub.image-puller-priority.fullname" . }} ++ {{- end }} ++ {{- with .Values.apps.jupyterhub.singleuser.nodeSelector }} ++ nodeSelector: ++ {{- . | toYaml | nindent 8 }} + {{- end }} +- nodeSelector: {{ toJson .Values.apps.jupyterhub.singleuser.nodeSelector }} + {{- with concat .Values.apps.jupyterhub.scheduling.userPods.tolerations .Values.apps.jupyterhub.singleuser.extraTolerations .Values.apps.jupyterhub.prePuller.extraTolerations }} + tolerations: + {{- . | toYaml | nindent 8 }} +@@ -127,6 +134,7 @@ spec: + {{- /* --- Conditionally pull profileList images --- */}} + {{- if .Values.apps.jupyterhub.prePuller.pullProfileListImages }} + {{- range $k, $container := .Values.apps.jupyterhub.singleuser.profileList }} ++ {{- /* profile's kubespawner_override */}} + {{- if $container.kubespawner_override }} + {{- if $container.kubespawner_override.image }} + - name: image-pull-singleuser-profilelist-{{ $k }} +@@ -145,13 +153,15 @@ spec: + {{- end }} + {{- end }} + {{- end }} +- {{- end }} +- {{- end }} +- +- {{- /* --- Pull extra images --- */}} +- {{- range $k, $v := .Values.apps.jupyterhub.prePuller.extraImages }} +- - name: image-pull-{{ $k }} +- image: {{ $v.name }}:{{ $v.tag }} ++ {{- /* kubespawner_override in profile's profile_options */}} ++ {{- if $container.profile_options }} ++ {{- range $option, $option_spec := $container.profile_options }} ++ {{- if $option_spec.choices }} ++ {{- range $choice, $choice_spec := $option_spec.choices }} ++ {{- if $choice_spec.kubespawner_override }} ++ {{- if $choice_spec.kubespawner_override.image }} ++ - name: image-pull-profile-{{ $k }}-option-{{ $option }}-{{ $choice }} ++ image: {{ $choice_spec.kubespawner_override.image }} + command: + - /bin/sh + - -c +@@ -163,13 +173,20 @@ spec: + {{- with $.Values.apps.jupyterhub.prePuller.containerSecurityContext }} + securityContext: + {{- . | toYaml | nindent 12 }} +- {{- end }} ++ {{- end }} ++ {{- end }} ++ {{- end }} ++ {{- end }} ++ {{- end }} ++ {{- end }} ++ {{- end }} ++ {{- end }} + {{- end }} + +- {{- /* --- Pull CloudHarness tasks images --- */}} +- {{- range $k, $v := ( index .Values "task-images" ) }} +- - name: image-pull-{{ $k | replace "-" "" }} +- image: {{ $v }} ++ {{- /* --- Pull extra images --- */}} ++ {{- range $k, $v := .Values.apps.jupyterhub.prePuller.extraImages }} ++ - name: image-pull-{{ $k }} ++ image: {{ $v.name }}:{{ $v.tag }} + command: + - /bin/sh + - -c +diff --git a/applications/jupyterhub/deploy/templates/image-puller/job.yaml b/applications/jupyterhub/deploy/templates/image-puller/job.yaml +index bdd9f63..cc6db3e 100755 +--- a/applications/jupyterhub/deploy/templates/image-puller/job.yaml ++++ b/applications/jupyterhub/deploy/templates/image-puller/job.yaml +@@ -28,16 +28,22 @@ spec: + labels: + {{- /* Changes here will cause the Job to restart the pods. */}} + {{- include "jupyterhub.matchLabels" . | nindent 8 }} ++ {{- with .Values.apps.jupyterhub.prePuller.labels }} ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + {{- with .Values.apps.jupyterhub.prePuller.annotations }} + annotations: + {{- . | toYaml | nindent 8 }} + {{- end }} + spec: + restartPolicy: Never +- {{- if .Values.apps.jupyterhub.rbac.enabled }} +- serviceAccountName: {{ include "jupyterhub.hook-image-awaiter.fullname" . }} ++ {{- with include "jupyterhub.hook-image-awaiter-serviceaccount.fullname" . }} ++ serviceAccountName: {{ . }} ++ {{- end }} ++ {{- with .Values.apps.jupyterhub.prePuller.hook.nodeSelector }} ++ nodeSelector: ++ {{- . | toYaml | nindent 8 }} + {{- end }} +- nodeSelector: {{ toJson .Values.apps.jupyterhub.prePuller.hook.nodeSelector }} + {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.prePuller.hook.tolerations }} + tolerations: + {{- . | toYaml | nindent 8 }} +@@ -58,6 +64,7 @@ spec: + - -api-server-address=https://kubernetes.default.svc:$(KUBERNETES_SERVICE_PORT) + - -namespace={{ .Release.Namespace }} + - -daemonset={{ include "jupyterhub.hook-image-puller.fullname" . }} ++ - -pod-scheduling-wait-duration={{ .Values.apps.jupyterhub.prePuller.hook.podSchedulingWaitDuration }} + {{- with .Values.apps.jupyterhub.prePuller.hook.containerSecurityContext }} + securityContext: + {{- . | toYaml | nindent 12 }} +diff --git a/applications/jupyterhub/deploy/templates/image-puller/priorityclass.yaml b/applications/jupyterhub/deploy/templates/image-puller/priorityclass.yaml +new file mode 100644 +index 0000000..1a3fca3 +--- /dev/null ++++ b/applications/jupyterhub/deploy/templates/image-puller/priorityclass.yaml +@@ -0,0 +1,18 @@ ++{{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} ++{{- if or .Values.apps.jupyterhub.prePuller.hook.enabled .Values.apps.jupyterhub.prePuller.continuous.enabled -}} ++apiVersion: scheduling.k8s.io/v1 ++kind: PriorityClass ++metadata: ++ name: {{ include "jupyterhub.image-puller-priority.fullname" . }} ++ annotations: ++ meta.helm.sh/release-name: "{{ .Release.Name }}" ++ meta.helm.sh/release-namespace: "{{ .Release.Namespace }}" ++ labels: ++ {{- include "jupyterhub.labels" . | nindent 4 }} ++value: {{ .Values.apps.jupyterhub.scheduling.podPriority.imagePullerPriority }} ++globalDefault: false ++description: >- ++ Enables [hook|continuous]-image-puller pods to fit on nodes even though they ++ are clogged by user-placeholder pods, while not evicting normal user pods. ++{{- end }} ++{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/image-puller/rbac.yaml b/applications/jupyterhub/deploy/templates/image-puller/rbac.yaml +index 95c86dd..5946896 100755 +--- a/applications/jupyterhub/deploy/templates/image-puller/rbac.yaml ++++ b/applications/jupyterhub/deploy/templates/image-puller/rbac.yaml +@@ -1,29 +1,8 @@ + {{- /* + Permissions to be used by the hook-image-awaiter job + */}} +-{{- if .Values.apps.jupyterhub.rbac.enabled }} +-{{- if (include "jupyterhub.imagePuller.daemonset.hook.install" .) }} +-{{- /* +-This service account... +-*/ -}} +-apiVersion: v1 +-kind: ServiceAccount +-metadata: +- name: {{ include "jupyterhub.hook-image-awaiter.fullname" . }} +- labels: +- {{- include "jupyterhub.labels" . | nindent 4 }} +- hub.jupyter.org/deletable: "true" +- annotations: +- "helm.sh/hook": pre-install,pre-upgrade +- "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +- "helm.sh/hook-weight": "0" +- {{- with .Values.apps.jupyterhub.prePuller.hook.serviceAccount.annotations }} +- {{- . | toYaml | nindent 4 }} +- {{- end }} +---- +-{{- /* +-... will be used by this role... +-*/}} ++{{- if .Values.apps.jupyterhub.rbac.create -}} ++{{- if (include "jupyterhub.imagePuller.daemonset.hook.install" .) -}} + kind: Role + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +@@ -56,7 +35,7 @@ metadata: + "helm.sh/hook-weight": "0" + subjects: + - kind: ServiceAccount +- name: {{ include "jupyterhub.hook-image-awaiter.fullname" . }} ++ name: {{ include "jupyterhub.hook-image-awaiter-serviceaccount.fullname" . }} + namespace: "{{ .Release.Namespace }}" + roleRef: + kind: Role +diff --git a/applications/jupyterhub/deploy/templates/image-puller/serviceaccount.yaml b/applications/jupyterhub/deploy/templates/image-puller/serviceaccount.yaml +new file mode 100644 +index 0000000..2e5fa72 +--- /dev/null ++++ b/applications/jupyterhub/deploy/templates/image-puller/serviceaccount.yaml +@@ -0,0 +1,21 @@ ++{{- /* ++ServiceAccount for the pre-puller hook's image-awaiter-job ++*/}} ++{{- if .Values.apps.jupyterhub.prePuller.hook.serviceAccount.create -}} ++{{- if (include "jupyterhub.imagePuller.daemonset.hook.install" .) -}} ++apiVersion: v1 ++kind: ServiceAccount ++metadata: ++ name: {{ include "jupyterhub.hook-image-awaiter-serviceaccount.fullname" . }} ++ labels: ++ {{- include "jupyterhub.labels" . | nindent 4 }} ++ hub.jupyter.org/deletable: "true" ++ annotations: ++ "helm.sh/hook": pre-install,pre-upgrade ++ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded ++ "helm.sh/hook-weight": "0" ++ {{- with .Values.apps.jupyterhub.prePuller.hook.serviceAccount.annotations }} ++ {{- . | toYaml | nindent 4 }} ++ {{- end }} ++{{- end }} ++{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/_README.txt b/applications/jupyterhub/deploy/templates/proxy/autohttps/_README.txt +deleted file mode 100755 +index 08bd7bb..0000000 +--- a/applications/jupyterhub/deploy/templates/proxy/autohttps/_README.txt ++++ /dev/null +@@ -1,9 +0,0 @@ +-# Automatic HTTPS Terminator +- +-This directory has Kubernetes objects for automatic Let's Encrypt Support. +-When enabled, we create a new deployment object that has an nginx-ingress +-and kube-lego container in it. This is responsible for requesting, +-storing and renewing certificates as needed from Let's Encrypt. +- +-The only change required outside of this directory is in the `proxy-public` +-service, which targets different hubs based on automatic HTTPS status. +\ No newline at end of file +diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/configmap.yaml b/applications/jupyterhub/deploy/templates/proxy/autohttps/configmap.yaml +deleted file mode 100755 +index 8d71a97..0000000 +--- a/applications/jupyterhub/deploy/templates/proxy/autohttps/configmap.yaml ++++ /dev/null +@@ -1,28 +0,0 @@ +-{{- $HTTPS := (and .Values.apps.jupyterhub.proxy.https.hosts .Values.apps.jupyterhub.proxy.https.enabled) }} +-{{- $autoHTTPS := (and $HTTPS (eq .Values.apps.jupyterhub.proxy.https.type "letsencrypt")) }} +-{{- if $autoHTTPS -}} +-{{- $_ := .Values.apps.jupyterhub.proxy.https.letsencrypt.contactEmail | required "proxy.https.letsencrypt.contactEmail is a required field" -}} +- +-# This configmap contains Traefik configuration files to be mounted. +-# - traefik.yaml will only be read during startup (static configuration) +-# - dynamic.yaml will be read on change (dynamic configuration) +-# +-# ref: https://docs.traefik.io/getting-started/configuration-overview/ +-# +-# The configuration files are first rendered with Helm templating to large YAML +-# strings. Then we use the fromYAML function on these strings to get an object, +-# that we in turn merge with user provided extra configuration. +-# +-kind: ConfigMap +-apiVersion: v1 +-metadata: +- name: {{ include "jupyterhub.autohttps.fullname" . }} +- labels: +- {{- include "jupyterhub.labels" . | nindent 4 }} +-data: +- traefik.yaml: | +- {{- include "jupyterhub.traefik.yaml" . | fromYaml | merge .Values.apps.jupyterhub.proxy.traefik.extraStaticConfig | toYaml | nindent 4 }} +- dynamic.yaml: | +- {{- include "jupyterhub.dynamic.yaml" . | fromYaml | merge .Values.apps.jupyterhub.proxy.traefik.extraDynamicConfig | toYaml | nindent 4 }} +- +-{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/deployment.yaml b/applications/jupyterhub/deploy/templates/proxy/autohttps/deployment.yaml +deleted file mode 100755 +index fcb062f..0000000 +--- a/applications/jupyterhub/deploy/templates/proxy/autohttps/deployment.yaml ++++ /dev/null +@@ -1,141 +0,0 @@ +-{{- $HTTPS := (and .Values.apps.jupyterhub.proxy.https.hosts .Values.apps.jupyterhub.proxy.https.enabled) }} +-{{- $autoHTTPS := (and $HTTPS (eq .Values.apps.jupyterhub.proxy.https.type "letsencrypt")) }} +-{{- if $autoHTTPS -}} +-apiVersion: apps/v1 +-kind: Deployment +-metadata: +- name: {{ include "jupyterhub.autohttps.fullname" . }} +- labels: +- {{- include "jupyterhub.labels" . | nindent 4 }} +-spec: +- replicas: 1 +- selector: +- matchLabels: +- {{- include "jupyterhub.matchLabels" . | nindent 6 }} +- template: +- metadata: +- labels: +- {{- include "jupyterhub.matchLabels" . | nindent 8 }} +- hub.jupyter.org/network-access-proxy-http: "true" +- {{- with .Values.apps.jupyterhub.proxy.traefik.labels }} +- {{- . | toYaml | nindent 8 }} +- {{- end }} +- annotations: +- # Only force a restart through a change to this checksum when the static +- # configuration is changed, as the dynamic can be updated after start. +- # Any disruptions to this deployment impacts everything, it is the +- # entrypoint of all network traffic. +- checksum/static-config: {{ include "jupyterhub.traefik.yaml" . | fromYaml | merge .Values.apps.jupyterhub.proxy.traefik.extraStaticConfig | toYaml | sha256sum }} +- spec: +- {{- if .Values.apps.jupyterhub.rbac.enabled }} +- serviceAccountName: {{ include "jupyterhub.autohttps.fullname" . }} +- {{- end }} +- {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} +- priorityClassName: {{ include "jupyterhub.priority.fullname" . }} +- {{- end }} +- nodeSelector: {{ toJson .Values.apps.jupyterhub.proxy.traefik.nodeSelector }} +- {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.proxy.traefik.tolerations }} +- tolerations: +- {{- . | toYaml | nindent 8 }} +- {{- end }} +- {{- include "jupyterhub.coreAffinity" . | nindent 6 }} +- volumes: +- - name: certificates +- emptyDir: {} +- - name: traefik-config +- configMap: +- name: {{ include "jupyterhub.autohttps.fullname" . }} +- {{- with .Values.apps.jupyterhub.proxy.traefik.extraVolumes }} +- {{- . | toYaml | nindent 8 }} +- {{- end }} +- {{- with include "jupyterhub.imagePullSecrets" (dict "root" . "image" .Values.apps.jupyterhub.proxy.traefik.image) }} +- imagePullSecrets: {{ . }} +- {{- end }} +- initContainers: +- - name: load-acme +- image: "{{ .Values.apps.jupyterhub.proxy.secretSync.image.name }}:{{ .Values.apps.jupyterhub.proxy.secretSync.image.tag }}" +- {{- with .Values.apps.jupyterhub.proxy.secretSync.image.pullPolicy }} +- imagePullPolicy: {{ . }} +- {{- end }} +- args: +- - load +- - {{ include "jupyterhub.proxy-public-tls.fullname" . }} +- - acme.json +- - /etc/acme/acme.json +- env: +- # We need this to get logs immediately +- - name: PYTHONUNBUFFERED +- value: "True" +- {{- with .Values.apps.jupyterhub.proxy.traefik.extraEnv }} +- {{- include "jupyterhub.extraEnv" . | nindent 12 }} +- {{- end }} +- volumeMounts: +- - name: certificates +- mountPath: /etc/acme +- {{- with .Values.apps.jupyterhub.proxy.secretSync.containerSecurityContext }} +- securityContext: +- {{- . | toYaml | nindent 12 }} +- {{- end }} +- containers: +- - name: traefik +- image: "{{ .Values.apps.jupyterhub.proxy.traefik.image.name }}:{{ .Values.apps.jupyterhub.proxy.traefik.image.tag }}" +- {{- with .Values.apps.jupyterhub.proxy.traefik.image.pullPolicy }} +- imagePullPolicy: {{ . }} +- {{- end }} +- {{- with .Values.apps.jupyterhub.proxy.traefik.resources }} +- resources: +- {{- . | toYaml | nindent 12 }} +- {{- end }} +- ports: +- - name: http +- containerPort: 8080 +- - name: https +- containerPort: 8443 +- {{- with .Values.apps.jupyterhub.proxy.traefik.extraPorts }} +- {{- . | toYaml | nindent 12 }} +- {{- end }} +- volumeMounts: +- - name: traefik-config +- mountPath: /etc/traefik +- - name: certificates +- mountPath: /etc/acme +- {{- with .Values.apps.jupyterhub.proxy.traefik.extraVolumeMounts }} +- {{- . | toYaml | nindent 12 }} +- {{- end }} +- {{- with .Values.apps.jupyterhub.proxy.traefik.extraEnv }} +- env: +- {{- include "jupyterhub.extraEnv" . | nindent 12 }} +- {{- end }} +- {{- with .Values.apps.jupyterhub.proxy.traefik.containerSecurityContext }} +- securityContext: +- {{- . | toYaml | nindent 12 }} +- {{- end }} +- - name: secret-sync +- image: "{{ .Values.apps.jupyterhub.proxy.secretSync.image.name }}:{{ .Values.apps.jupyterhub.proxy.secretSync.image.tag }}" +- {{- with .Values.apps.jupyterhub.proxy.secretSync.image.pullPolicy }} +- imagePullPolicy: {{ . }} +- {{- end }} +- args: +- - watch-save +- - --label=app={{ include "jupyterhub.appLabel" . }} +- - --label=release={{ .Release.Name }} +- - --label=chart={{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} +- - --label=heritage=secret-sync +- - {{ include "jupyterhub.proxy-public-tls.fullname" . }} +- - acme.json +- - /etc/acme/acme.json +- env: +- # We need this to get logs immediately +- - name: PYTHONUNBUFFERED +- value: "True" +- volumeMounts: +- - name: certificates +- mountPath: /etc/acme +- {{- with .Values.apps.jupyterhub.proxy.secretSync.containerSecurityContext }} +- securityContext: +- {{- . | toYaml | nindent 12 }} +- {{- end }} +- {{- with .Values.apps.jupyterhub.proxy.traefik.extraPodSpec }} +- {{- . | toYaml | nindent 6 }} +- {{- end }} +-{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/rbac.yaml b/applications/jupyterhub/deploy/templates/proxy/autohttps/rbac.yaml +deleted file mode 100755 +index ea43b67..0000000 +--- a/applications/jupyterhub/deploy/templates/proxy/autohttps/rbac.yaml ++++ /dev/null +@@ -1,40 +0,0 @@ +-{{- $HTTPS := (and .Values.apps.jupyterhub.proxy.https.hosts .Values.apps.jupyterhub.proxy.https.enabled) }} +-{{- $autoHTTPS := (and $HTTPS (eq .Values.apps.jupyterhub.proxy.https.type "letsencrypt")) }} +-{{- if (and $autoHTTPS .Values.apps.jupyterhub.rbac.enabled) -}} +-apiVersion: rbac.authorization.k8s.io/v1 +-kind: Role +-metadata: +- name: {{ include "jupyterhub.autohttps.fullname" . }} +- labels: +- {{- include "jupyterhub.labels" . | nindent 4 }} +- {{- with .Values.apps.jupyterhub.proxy.traefik.serviceAccount.annotations }} +- annotations: +- {{- . | toYaml | nindent 4 }} +- {{- end }} +-rules: +-- apiGroups: [""] +- resources: ["secrets"] +- verbs: ["get", "patch", "list", "create"] +---- +-apiVersion: rbac.authorization.k8s.io/v1 +-kind: RoleBinding +-metadata: +- name: {{ include "jupyterhub.autohttps.fullname" . }} +- labels: +- {{- include "jupyterhub.labels" . | nindent 4 }} +-subjects: +-- kind: ServiceAccount +- name: {{ include "jupyterhub.autohttps.fullname" . }} +- apiGroup: +-roleRef: +- kind: Role +- name: {{ include "jupyterhub.autohttps.fullname" . }} +- apiGroup: rbac.authorization.k8s.io +---- +-apiVersion: v1 +-kind: ServiceAccount +-metadata: +- name: {{ include "jupyterhub.autohttps.fullname" . }} +- labels: +- {{- include "jupyterhub.labels" . | nindent 4 }} +-{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/proxy/autohttps/service.yaml b/applications/jupyterhub/deploy/templates/proxy/autohttps/service.yaml +deleted file mode 100755 +index d57c135..0000000 +--- a/applications/jupyterhub/deploy/templates/proxy/autohttps/service.yaml ++++ /dev/null +@@ -1,25 +0,0 @@ +-{{- $HTTPS := (and .Values.apps.jupyterhub.proxy.https.hosts .Values.apps.jupyterhub.proxy.https.enabled) }} +-{{- $autoHTTPS := (and $HTTPS (eq .Values.apps.jupyterhub.proxy.https.type "letsencrypt")) }} +-{{- if $autoHTTPS -}} +-apiVersion: v1 +-kind: Service +-metadata: +- name: {{ include "jupyterhub.proxy-http.fullname" . }} +- labels: +- {{- include "jupyterhub.labels" . | nindent 4 }} +- {{- with .Values.apps.jupyterhub.proxy.service.labels }} +- {{- . | toYaml | nindent 4 }} +- {{- end }} +- {{- with .Values.apps.jupyterhub.proxy.service.annotations }} +- annotations: +- {{- . | toYaml | nindent 4 }} +- {{- end }} +-spec: +- type: ClusterIP +- selector: +- {{- $_ := merge (dict "componentLabel" "proxy") . }} +- {{- include "jupyterhub.matchLabels" $_ | nindent 4 }} +- ports: +- - port: 8000 +- targetPort: http +-{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/proxy/deployment.yaml b/applications/jupyterhub/deploy/templates/proxy/deployment.yaml +index 6d63ba8..bb37b8f 100755 +--- a/applications/jupyterhub/deploy/templates/proxy/deployment.yaml ++++ b/applications/jupyterhub/deploy/templates/proxy/deployment.yaml +@@ -7,6 +7,9 @@ metadata: + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} + spec: ++ {{- if typeIs "int" .Values.apps.jupyterhub.proxy.chp.revisionHistoryLimit }} ++ revisionHistoryLimit: {{ .Values.apps.jupyterhub.proxy.chp.revisionHistoryLimit }} ++ {{- end }} + replicas: 1 + selector: + matchLabels: +@@ -35,7 +38,7 @@ spec: + # match the k8s Secret during the first upgrade following an auth_token + # was generated. + checksum/auth-token: {{ include "jupyterhub.hub.config.ConfigurableHTTPProxy.auth_token" . | sha256sum | trunc 4 | quote }} +- checksum/proxy-secret: {{ include (print $.Template.BasePath "/jupyterhub/hub/secret.yaml") . | sha256sum }} ++ checksum/proxy-secret: {{ include (print $.Template.BasePath "/jupyterhub/proxy/secret.yaml") . | sha256sum | quote }} + {{- with .Values.apps.jupyterhub.proxy.annotations }} + {{- . | toYaml | nindent 8 }} + {{- end }} +@@ -44,7 +47,10 @@ spec: + {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} + priorityClassName: {{ include "jupyterhub.priority.fullname" . }} + {{- end }} +- nodeSelector: {{ toJson .Values.apps.jupyterhub.proxy.chp.nodeSelector }} ++ {{- with .Values.apps.jupyterhub.proxy.chp.nodeSelector }} ++ nodeSelector: ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.proxy.chp.tolerations }} + tolerations: + {{- . | toYaml | nindent 8 }} +@@ -135,6 +141,8 @@ spec: + livenessProbe: + initialDelaySeconds: {{ .Values.apps.jupyterhub.proxy.chp.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.apps.jupyterhub.proxy.chp.livenessProbe.periodSeconds }} ++ timeoutSeconds: {{ .Values.apps.jupyterhub.proxy.chp.livenessProbe.timeoutSeconds }} ++ failureThreshold: {{ .Values.apps.jupyterhub.proxy.chp.livenessProbe.failureThreshold }} + httpGet: + path: /_chp_healthz + {{- if or $manualHTTPS $manualHTTPSwithsecret }} +@@ -149,6 +157,8 @@ spec: + readinessProbe: + initialDelaySeconds: {{ .Values.apps.jupyterhub.proxy.chp.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.apps.jupyterhub.proxy.chp.readinessProbe.periodSeconds }} ++ timeoutSeconds: {{ .Values.apps.jupyterhub.proxy.chp.readinessProbe.timeoutSeconds }} ++ failureThreshold: {{ .Values.apps.jupyterhub.proxy.chp.readinessProbe.failureThreshold }} + httpGet: + path: /_chp_healthz + {{- if or $manualHTTPS $manualHTTPSwithsecret }} +diff --git a/applications/jupyterhub/deploy/templates/proxy/netpol.yaml b/applications/jupyterhub/deploy/templates/proxy/netpol.yaml +index adc8277..88a00be 100755 +--- a/applications/jupyterhub/deploy/templates/proxy/netpol.yaml ++++ b/applications/jupyterhub/deploy/templates/proxy/netpol.yaml +@@ -85,32 +85,24 @@ spec: + + egress: + # proxy --> hub +- - ports: +- - port: 8081 +- to: ++ - to: + - podSelector: + matchLabels: + {{- $_ := merge (dict "componentLabel" "hub") . }} + {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} ++ ports: ++ - port: 8081 + + # proxy --> singleuser-server +- - ports: +- - port: 8888 +- to: ++ - to: + - podSelector: + matchLabels: + {{- $_ := merge (dict "componentLabel" "singleuser-server") . }} + {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} ++ ports: ++ - port: 8888 + +- # proxy --> Kubernetes internal DNS +- - ports: +- - protocol: UDP +- port: 53 +- - protocol: TCP +- port: 53 +- +- {{- with .Values.apps.jupyterhub.proxy.chp.networkPolicy.egress }} +- # proxy --> depends, but the default is everything +- {{- . | toYaml | nindent 4 }} ++ {{- with (include "jupyterhub.networkPolicy.renderEgressRules" (list . .Values.apps.jupyterhub.proxy.chp.networkPolicy)) }} ++ {{- . | nindent 4 }} + {{- end }} + {{- end }} +diff --git a/applications/jupyterhub/deploy/templates/proxy/pdb.yaml b/applications/jupyterhub/deploy/templates/proxy/pdb.yaml +index 1846a3b..155895b 100755 +--- a/applications/jupyterhub/deploy/templates/proxy/pdb.yaml ++++ b/applications/jupyterhub/deploy/templates/proxy/pdb.yaml +@@ -1,9 +1,5 @@ + {{- if .Values.apps.jupyterhub.proxy.chp.pdb.enabled -}} +-{{- if .Capabilities.APIVersions.Has "policy/v1" }} + apiVersion: policy/v1 +-{{- else }} +-apiVersion: policy/v1beta1 +-{{- end }} + kind: PodDisruptionBudget + metadata: + name: {{ include "jupyterhub.proxy.fullname" . }} +diff --git a/applications/jupyterhub/deploy/templates/proxy/service.yaml b/applications/jupyterhub/deploy/templates/proxy/service.yaml +index 0d9ca5b..f634ba9 100755 +--- a/applications/jupyterhub/deploy/templates/proxy/service.yaml ++++ b/applications/jupyterhub/deploy/templates/proxy/service.yaml +@@ -35,12 +35,15 @@ metadata: + {{- end }} + spec: + selector: ++ # This service will target the autohttps pod if autohttps is configured, and ++ # the proxy pod if not. When autohttps is configured, the service proxy-http ++ # will be around to target the proxy pod directly. + {{- if $autoHTTPS }} +- component: autohttps ++ {{- $_ := merge (dict "componentLabel" "autohttps") . -}} ++ {{- include "jupyterhub.matchLabels" $_ | nindent 4 }} + {{- else }} +- component: proxy ++ {{- include "jupyterhub.matchLabels" . | nindent 4 }} + {{- end }} +- release: {{ .Release.Name }} + ports: + {{- if $HTTPS }} + - name: https +diff --git a/applications/jupyterhub/deploy/templates/scheduling/priorityclass.yaml b/applications/jupyterhub/deploy/templates/scheduling/priorityclass.yaml +index 588cf19..1bed905 100755 +--- a/applications/jupyterhub/deploy/templates/scheduling/priorityclass.yaml ++++ b/applications/jupyterhub/deploy/templates/scheduling/priorityclass.yaml +@@ -4,22 +4,9 @@ kind: PriorityClass + metadata: + name: {{ include "jupyterhub.priority.fullname" . }} + annotations: +- # FIXME: PriorityClasses must be added before the other resources reference +- # them, and in the past a workaround was needed to accomplish this: +- # to make the resource a Helm hook. +- # +- # To transition this resource to no longer be a Helm hook resource, +- # we explicitly add ownership annotations/labels (in 1.0.0) which +- # will allow a future upgrade (in 2.0.0) to remove all hook and +- # ownership annotations/labels. +- # +- helm.sh/hook: pre-install,pre-upgrade +- helm.sh/hook-delete-policy: before-hook-creation +- helm.sh/hook-weight: "-100" + meta.helm.sh/release-name: "{{ .Release.Name }}" + meta.helm.sh/release-namespace: "{{ .Release.Namespace }}" + labels: +- app.kubernetes.io/managed-by: Helm + {{- $_ := merge (dict "componentLabel" "default-priority") . }} + {{- include "jupyterhub.labels" $_ | nindent 4 }} + value: {{ .Values.apps.jupyterhub.scheduling.podPriority.defaultPriority }} +diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/pdb.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/pdb.yaml +index b1dc6c5..800ac20 100755 +--- a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/pdb.yaml ++++ b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/pdb.yaml +@@ -3,11 +3,7 @@ The cluster autoscaler should be allowed to evict and reschedule these pods if + it would help in order to scale down a node. + */}} + {{- if .Values.apps.jupyterhub.scheduling.userPlaceholder.enabled -}} +-{{- if .Capabilities.APIVersions.Has "policy/v1" }} + apiVersion: policy/v1 +-{{- else }} +-apiVersion: policy/v1beta1 +-{{- end }} + kind: PodDisruptionBudget + metadata: + name: {{ include "jupyterhub.user-placeholder.fullname" . }} +diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/priorityclass.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/priorityclass.yaml +index e03497d..688e217 100755 +--- a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/priorityclass.yaml ++++ b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/priorityclass.yaml +@@ -5,22 +5,9 @@ kind: PriorityClass + metadata: + name: {{ include "jupyterhub.user-placeholder-priority.fullname" . }} + annotations: +- # FIXME: PriorityClasses must be added before the other resources reference +- # them, and in the past a workaround was needed to accomplish this: +- # to make the resource a Helm hook. +- # +- # To transition this resource to no longer be a Helm hook resource, +- # we explicitly add ownership annotations/labels (in 1.0.0) which +- # will allow a future upgrade (in 2.0.0) to remove all hook and +- # ownership annotations/labels. +- # +- helm.sh/hook: pre-install,pre-upgrade +- helm.sh/hook-delete-policy: before-hook-creation +- helm.sh/hook-weight: "-100" + meta.helm.sh/release-name: "{{ .Release.Name }}" + meta.helm.sh/release-namespace: "{{ .Release.Namespace }}" + labels: +- app.kubernetes.io/managed-by: Helm + {{- include "jupyterhub.labels" . | nindent 4 }} + value: {{ .Values.apps.jupyterhub.scheduling.podPriority.userPlaceholderPriority }} + globalDefault: false +diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/statefulset.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/statefulset.yaml +index 114f626..c243bee 100755 +--- a/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/statefulset.yaml ++++ b/applications/jupyterhub/deploy/templates/scheduling/user-placeholder/statefulset.yaml +@@ -16,6 +16,9 @@ metadata: + {{- include "jupyterhub.labels" . | nindent 4 }} + spec: + podManagementPolicy: Parallel ++ {{- if typeIs "int" .Values.apps.jupyterhub.scheduling.userPlaceholder.revisionHistoryLimit }} ++ revisionHistoryLimit: {{ .Values.apps.jupyterhub.scheduling.userPlaceholder.revisionHistoryLimit }} ++ {{- end }} + replicas: {{ .Values.apps.jupyterhub.scheduling.userPlaceholder.replicas }} + selector: + matchLabels: +@@ -23,9 +26,16 @@ spec: + serviceName: {{ include "jupyterhub.user-placeholder.fullname" . }} + template: + metadata: ++ {{- with .Values.apps.jupyterhub.scheduling.userPlaceholder.annotations }} ++ annotations: ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + labels: + {{- /* Changes here will cause the Deployment to restart the pods. */}} + {{- include "jupyterhub.matchLabels" . | nindent 8 }} ++ {{- with .Values.apps.jupyterhub.scheduling.userPlaceholder.labels }} ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + spec: + {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} + priorityClassName: {{ include "jupyterhub.user-placeholder-priority.fullname" . }} +@@ -33,7 +43,10 @@ spec: + {{- if .Values.apps.jupyterhub.scheduling.userScheduler.enabled }} + schedulerName: {{ include "jupyterhub.user-scheduler.fullname" . }} + {{- end }} +- nodeSelector: {{ toJson .Values.apps.jupyterhub.singleuser.nodeSelector }} ++ {{- with .Values.apps.jupyterhub.singleuser.nodeSelector }} ++ nodeSelector: ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + {{- with concat .Values.apps.jupyterhub.scheduling.userPods.tolerations .Values.apps.jupyterhub.singleuser.extraTolerations }} + tolerations: + {{- . | toYaml | nindent 8 }} +diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/configmap.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/configmap.yaml +index ef8a37f..3e83b44 100755 +--- a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/configmap.yaml ++++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/configmap.yaml +@@ -6,16 +6,28 @@ metadata: + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} + data: +- # ref: https://kubernetes.io/docs/reference/scheduling/config/ ++ {{- /* ++ This is configuration of a k8s official kube-scheduler binary running in the ++ user-scheduler. ++ ++ ref: https://kubernetes.io/docs/reference/scheduling/config/ ++ ref: https://kubernetes.io/docs/reference/config-api/kube-scheduler-config.v1/ ++ */}} + config.yaml: | +- apiVersion: kubescheduler.config.k8s.io/v1beta1 ++ apiVersion: kubescheduler.config.k8s.io/v1 + kind: KubeSchedulerConfiguration + leaderElection: +- resourceLock: endpoints ++ resourceLock: leases + resourceName: {{ include "jupyterhub.user-scheduler-lock.fullname" . }} + resourceNamespace: "{{ .Release.Namespace }}" + profiles: + - schedulerName: {{ include "jupyterhub.user-scheduler.fullname" . }} ++ {{- with .Values.apps.jupyterhub.scheduling.userScheduler.plugins }} + plugins: +- {{- .Values.apps.jupyterhub.scheduling.userScheduler.plugins | toYaml | nindent 10 }} ++ {{- . | toYaml | nindent 10 }} ++ {{- end }} ++ {{- with .Values.apps.jupyterhub.scheduling.userScheduler.pluginConfig }} ++ pluginConfig: ++ {{- . | toYaml | nindent 10 }} ++ {{- end }} + {{- end }} +diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/deployment.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/deployment.yaml +index 1bcaf31..f22d0de 100755 +--- a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/deployment.yaml ++++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/deployment.yaml +@@ -6,6 +6,9 @@ metadata: + labels: + {{- include "jupyterhub.labels" . | nindent 4 }} + spec: ++ {{- if typeIs "int" .Values.apps.jupyterhub.scheduling.userScheduler.revisionHistoryLimit }} ++ revisionHistoryLimit: {{ .Values.apps.jupyterhub.scheduling.userScheduler.revisionHistoryLimit }} ++ {{- end }} + replicas: {{ .Values.apps.jupyterhub.scheduling.userScheduler.replicas }} + selector: + matchLabels: +@@ -14,16 +17,25 @@ spec: + metadata: + labels: + {{- include "jupyterhub.matchLabels" . | nindent 8 }} ++ {{- with .Values.apps.jupyterhub.scheduling.userScheduler.labels }} ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + annotations: + checksum/config-map: {{ include (print $.Template.BasePath "/jupyterhub/scheduling/user-scheduler/configmap.yaml") . | sha256sum }} ++ {{- with .Values.apps.jupyterhub.scheduling.userScheduler.annotations }} ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + spec: +- {{- if .Values.apps.jupyterhub.rbac.enabled }} +- serviceAccountName: {{ include "jupyterhub.user-scheduler-deploy.fullname" . }} ++ {{ with include "jupyterhub.user-scheduler-serviceaccount.fullname" . }} ++ serviceAccountName: {{ . }} + {{- end }} + {{- if .Values.apps.jupyterhub.scheduling.podPriority.enabled }} + priorityClassName: {{ include "jupyterhub.priority.fullname" . }} + {{- end }} +- nodeSelector: {{ toJson .Values.apps.jupyterhub.scheduling.userScheduler.nodeSelector }} ++ {{- with .Values.apps.jupyterhub.scheduling.userScheduler.nodeSelector }} ++ nodeSelector: ++ {{- . | toYaml | nindent 8 }} ++ {{- end }} + {{- with concat .Values.apps.jupyterhub.scheduling.corePods.tolerations .Values.apps.jupyterhub.scheduling.userScheduler.tolerations }} + tolerations: + {{- . | toYaml | nindent 8 }} +@@ -44,13 +56,6 @@ spec: + {{- end }} + command: + - /usr/local/bin/kube-scheduler +- # NOTE: --leader-elect-... (new) and --lock-object-... (deprecated) +- # flags are silently ignored in favor of whats defined in the +- # passed KubeSchedulerConfiguration whenever --config is +- # passed. +- # +- # ref: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/ +- # + # NOTE: --authentication-skip-lookup=true is used to avoid a + # seemingly harmless error, if we need to not skip + # "authentication lookup" in the future, see the linked issue. +@@ -65,12 +70,14 @@ spec: + livenessProbe: + httpGet: + path: /healthz +- port: 10251 ++ scheme: HTTPS ++ port: 10259 + initialDelaySeconds: 15 + readinessProbe: + httpGet: + path: /healthz +- port: 10251 ++ scheme: HTTPS ++ port: 10259 + {{- with .Values.apps.jupyterhub.scheduling.userScheduler.resources }} + resources: + {{- . | toYaml | nindent 12 }} +diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/pdb.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/pdb.yaml +index 04f2af8..2c9c6de 100755 +--- a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/pdb.yaml ++++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/pdb.yaml +@@ -1,9 +1,5 @@ + {{- if and .Values.apps.jupyterhub.scheduling.userScheduler.enabled .Values.apps.jupyterhub.scheduling.userScheduler.pdb.enabled -}} +-{{- if .Capabilities.APIVersions.Has "policy/v1" }} + apiVersion: policy/v1 +-{{- else }} +-apiVersion: policy/v1beta1 +-{{- end }} + kind: PodDisruptionBudget + metadata: + name: {{ include "jupyterhub.user-scheduler-deploy.fullname" . }} +diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/rbac.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/rbac.yaml +index 083e065..9c7fab7 100755 +--- a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/rbac.yaml ++++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/rbac.yaml +@@ -1,16 +1,5 @@ + {{- if .Values.apps.jupyterhub.scheduling.userScheduler.enabled -}} +-{{- if .Values.apps.jupyterhub.rbac.enabled }} +-apiVersion: v1 +-kind: ServiceAccount +-metadata: +- name: {{ include "jupyterhub.user-scheduler-deploy.fullname" . }} +- labels: +- {{- include "jupyterhub.labels" . | nindent 4 }} +- {{- with .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.annotations }} +- annotations: +- {{- . | toYaml | nindent 4 }} +- {{- end }} +---- ++{{- if .Values.apps.jupyterhub.rbac.create -}} + kind: ClusterRole + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +@@ -19,13 +8,23 @@ metadata: + {{- include "jupyterhub.labels" . | nindent 4 }} + rules: + # Copied from the system:kube-scheduler ClusterRole of the k8s version +- # matching the kube-scheduler binary we use. A modification of two resource +- # name references from kube-scheduler to user-scheduler-lock was made. ++ # matching the kube-scheduler binary we use. A modification has been made to ++ # resourceName fields to remain relevant for how we have named our resources ++ # in this Helm chart. + # +- # NOTE: These rules have been unchanged between 1.12 and 1.15, then changed in +- # 1.16 and in 1.17, but unchanged in 1.18 and 1.19. ++ # NOTE: These rules have been: ++ # - unchanged between 1.12 and 1.15 ++ # - changed in 1.16 ++ # - changed in 1.17 ++ # - unchanged between 1.18 and 1.20 ++ # - changed in 1.21: get/list/watch permission for namespace, ++ # csidrivers, csistoragecapacities was added. ++ # - unchanged between 1.22 and 1.27 ++ # - changed in 1.28: permissions to get/update lock endpoint resource ++ # removed ++ # - unchanged between 1.28 and 1.29 + # +- # ref: https://github.com/kubernetes/kubernetes/blob/v1.19.0/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml#L696-L829 ++ # ref: https://github.com/kubernetes/kubernetes/blob/v1.29.0/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml#L721-L862 + - apiGroups: + - "" + - events.k8s.io +@@ -50,21 +49,6 @@ rules: + verbs: + - get + - update +- - apiGroups: +- - "" +- resources: +- - endpoints +- verbs: +- - create +- - apiGroups: +- - "" +- resourceNames: +- - {{ include "jupyterhub.user-scheduler-lock.fullname" . }} +- resources: +- - endpoints +- verbs: +- - get +- - update + - apiGroups: + - "" + resources: +@@ -159,13 +143,37 @@ rules: + - get + - list + - watch ++ - apiGroups: ++ - "" ++ resources: ++ - namespaces ++ verbs: ++ - get ++ - list ++ - watch ++ - apiGroups: ++ - storage.k8s.io ++ resources: ++ - csidrivers ++ verbs: ++ - get ++ - list ++ - watch ++ - apiGroups: ++ - storage.k8s.io ++ resources: ++ - csistoragecapacities ++ verbs: ++ - get ++ - list ++ - watch + + # Copied from the system:volume-scheduler ClusterRole of the k8s version + # matching the kube-scheduler binary we use. + # +- # NOTE: These rules have not changed between 1.12 and 1.19. ++ # NOTE: These rules have not changed between 1.12 and 1.29. + # +- # ref: https://github.com/kubernetes/kubernetes/blob/v1.19.0/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml#L1213-L1240 ++ # ref: https://github.com/kubernetes/kubernetes/blob/v1.29.0/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml#L1283-L1310 + - apiGroups: + - "" + resources: +@@ -203,7 +211,7 @@ metadata: + {{- include "jupyterhub.labels" . | nindent 4 }} + subjects: + - kind: ServiceAccount +- name: {{ include "jupyterhub.user-scheduler-deploy.fullname" . }} ++ name: {{ include "jupyterhub.user-scheduler-serviceaccount.fullname" . }} + namespace: "{{ .Release.Namespace }}" + roleRef: + kind: ClusterRole +diff --git a/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/serviceaccount.yaml b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/serviceaccount.yaml +new file mode 100644 +index 0000000..67618b0 +--- /dev/null ++++ b/applications/jupyterhub/deploy/templates/scheduling/user-scheduler/serviceaccount.yaml +@@ -0,0 +1,14 @@ ++{{- if .Values.apps.jupyterhub.scheduling.userScheduler.enabled -}} ++{{- if .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.create -}} ++apiVersion: v1 ++kind: ServiceAccount ++metadata: ++ name: {{ include "jupyterhub.user-scheduler-serviceaccount.fullname" . }} ++ labels: ++ {{- include "jupyterhub.labels" . | nindent 4 }} ++ {{- with .Values.apps.jupyterhub.scheduling.userScheduler.serviceAccount.annotations }} ++ annotations: ++ {{- . | toYaml | nindent 4 }} ++ {{- end }} ++{{- end }} ++{{- end }} +diff --git a/applications/jupyterhub/deploy/templates/singleuser/netpol.yaml b/applications/jupyterhub/deploy/templates/singleuser/netpol.yaml +index 3dfb137..931a150 100755 +--- a/applications/jupyterhub/deploy/templates/singleuser/netpol.yaml ++++ b/applications/jupyterhub/deploy/templates/singleuser/netpol.yaml +@@ -62,23 +62,38 @@ spec: + + egress: + # singleuser-server --> hub +- - ports: +- - port: 8081 +- to: ++ - to: + - podSelector: + matchLabels: + {{- $_ := merge (dict "componentLabel" "hub") . }} + {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} ++ ports: ++ - port: 8081 + +- # singleuser-server --> Kubernetes internal DNS +- - ports: +- - protocol: UDP +- port: 53 +- - protocol: TCP +- port: 53 ++ # singleuser-server --> proxy ++ # singleuser-server --> autohttps ++ # ++ # While not critical for core functionality, a user or library code may rely ++ # on communicating with the proxy or autohttps pods via a k8s Service it can ++ # detected from well known environment variables. ++ # ++ - to: ++ - podSelector: ++ matchLabels: ++ {{- $_ := merge (dict "componentLabel" "proxy") . }} ++ {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} ++ ports: ++ - port: 8000 ++ - to: ++ - podSelector: ++ matchLabels: ++ {{- $_ := merge (dict "componentLabel" "autohttps") . }} ++ {{- include "jupyterhub.matchLabels" $_ | nindent 14 }} ++ ports: ++ - port: 8080 ++ - port: 8443 + +- {{- with .Values.apps.jupyterhub.singleuser.networkPolicy.egress }} +- # singleuser-server --> depends, but the default is everything +- {{- . | toYaml | nindent 4 }} ++ {{- with (include "jupyterhub.networkPolicy.renderEgressRules" (list . .Values.apps.jupyterhub.singleuser.networkPolicy)) }} ++ {{- . | nindent 4 }} + {{- end }} + {{- end }} +diff --git a/applications/jupyterhub/deploy/templates/singleuser/secret.yaml b/applications/jupyterhub/deploy/templates/singleuser/secret.yaml +new file mode 100644 +index 0000000..e6eab9b +--- /dev/null ++++ b/applications/jupyterhub/deploy/templates/singleuser/secret.yaml +@@ -0,0 +1,17 @@ ++{{- if .Values.apps.jupyterhub.singleuser.extraFiles }} ++kind: Secret ++apiVersion: v1 ++metadata: ++ name: {{ include "jupyterhub.singleuser.fullname" . }} ++ labels: ++ {{- include "jupyterhub.labels" . | nindent 4 }} ++type: Opaque ++{{- with include "jupyterhub.extraFiles.data" .Values.apps.jupyterhub.singleuser.extraFiles }} ++data: ++ {{- . | nindent 2 }} ++{{- end }} ++{{- with include "jupyterhub.extraFiles.stringData" .Values.apps.jupyterhub.singleuser.extraFiles }} ++stringData: ++ {{- . | nindent 2 }} ++{{- end }} ++{{- end }} +diff --git a/applications/jupyterhub/deploy/values.schema.yaml b/applications/jupyterhub/deploy/values.schema.yaml +new file mode 100644 +index 0000000..69c13a8 +--- /dev/null ++++ b/applications/jupyterhub/deploy/values.schema.yaml +@@ -0,0 +1,3014 @@ ++# This schema (a jsonschema in YAML format) is used to generate ++# values.schema.json which is packaged with the Helm chart for client side ++# validation by helm of values before template rendering. ++# ++# This schema is also used by our documentation system to build the ++# configuration reference section based on the description fields. See ++# docs/source/conf.py for that logic! ++# ++# We look to document everything we have default values for in values.yaml, but ++# we don't look to enforce the perfect validation logic within this file. ++# ++# ref: https://json-schema.org/learn/getting-started-step-by-step.html ++# ++$schema: http://json-schema.org/draft-07/schema# ++type: object ++additionalProperties: false ++required: ++ - imagePullSecrets ++ - hub ++ - proxy ++ - singleuser ++ - ingress ++ - prePuller ++ - custom ++ - cull ++ - debug ++ - rbac ++ - global ++properties: ++ enabled: ++ type: [boolean, "null"] ++ description: | ++ `enabled` is ignored by the jupyterhub chart itself, but a chart depending ++ on the jupyterhub chart conditionally can make use this config option as ++ the condition. ++ fullnameOverride: ++ type: [string, "null"] ++ description: | ++ fullnameOverride and nameOverride allow you to adjust how the resources ++ part of the Helm chart are named. ++ ++ Name format | Resource types | fullnameOverride | nameOverride | Note ++ ------------------------- | -------------- | ---------------- | ------------ | - ++ component | namespaced | `""` | * | Default ++ release-component | cluster wide | `""` | * | Default ++ fullname-component | * | str | * | - ++ release-component | * | null | `""` | - ++ release-(name-)component | * | null | str | omitted if contained in release ++ release-(chart-)component | * | null | null | omitted if contained in release ++ ++ ```{admonition} Warning! ++ :class: warning ++ Changing fullnameOverride or nameOverride after the initial installation ++ of the chart isn't supported. Changing their values likely leads to a ++ reset of non-external JupyterHub databases, abandonment of users' storage, ++ and severed couplings to currently running user pods. ++ ``` ++ ++ If you are a developer of a chart depending on this chart, you should ++ avoid hardcoding names. If you want to reference the name of a resource in ++ this chart from a parent helm chart's template, you can make use of the ++ global named templates instead. ++ ++ ```yaml ++ # some pod definition of a parent chart helm template ++ schedulerName: {{ include "jupyterhub.user-scheduler.fullname" . }} ++ ``` ++ ++ To access them from a container, you can also rely on the hub ConfigMap ++ that contains entries of all the resource names. ++ ++ ```yaml ++ # some container definition in a parent chart helm template ++ env: ++ - name: SCHEDULER_NAME ++ valueFrom: ++ configMapKeyRef: ++ name: {{ include "jupyterhub.user-scheduler.fullname" . }} ++ key: user-scheduler ++ ``` ++ ++ nameOverride: ++ type: [string, "null"] ++ description: | ++ See the documentation under [`fullnameOverride`](schema_fullnameOverride). ++ ++ imagePullSecret: ++ type: object ++ required: [create] ++ if: ++ properties: ++ create: ++ const: true ++ then: ++ additionalProperties: false ++ required: [registry, username, password] ++ description: | ++ This is configuration to create a k8s Secret resource of `type: ++ kubernetes.io/dockerconfigjson`, with credentials to pull images from a ++ private image registry. If you opt to do so, it will be available for use ++ by all pods in their respective `spec.imagePullSecrets` alongside other ++ k8s Secrets defined in `imagePullSecrets` or the pod respective ++ `...image.pullSecrets` configuration. ++ ++ In other words, using this configuration option can automate both the ++ otherwise manual creation of a k8s Secret and the otherwise manual ++ configuration to reference this k8s Secret in all the pods of the Helm ++ chart. ++ ++ ```sh ++ # you won't need to create a k8s Secret manually... ++ kubectl create secret docker-registry image-pull-secret \ ++ --docker-server= \ ++ --docker-username= \ ++ --docker-email= \ ++ --docker-password= ++ ``` ++ ++ If you just want to let all Pods reference an existing secret, use the ++ [`imagePullSecrets`](schema_imagePullSecrets) configuration instead. ++ properties: ++ create: ++ type: boolean ++ description: | ++ Toggle the creation of the k8s Secret with provided credentials to ++ access a private image registry. ++ automaticReferenceInjection: ++ type: boolean ++ description: | ++ Toggle the automatic reference injection of the created Secret to all ++ pods' `spec.imagePullSecrets` configuration. ++ registry: ++ type: string ++ description: | ++ Name of the private registry you want to create a credential set for. ++ It will default to Docker Hub's image registry. ++ ++ Examples: ++ - https://index.docker.io/v1/ ++ - quay.io ++ - eu.gcr.io ++ - alexmorreale.privatereg.net ++ username: ++ type: string ++ description: | ++ Name of the user you want to use to connect to your private registry. ++ ++ For external gcr.io, you will use the `_json_key`. ++ ++ Examples: ++ - alexmorreale ++ - alex@pfc.com ++ - _json_key ++ password: ++ type: string ++ description: | ++ Password for the private image registry's user. ++ ++ Examples: ++ - plaintextpassword ++ - abc123SECRETzyx098 ++ ++ For gcr.io registries the password will be a big JSON blob for a ++ Google cloud service account, it should look something like below. ++ ++ ```yaml ++ password: |- ++ { ++ "type": "service_account", ++ "project_id": "jupyter-se", ++ "private_key_id": "f2ba09118a8d3123b3321bd9a7d6d0d9dc6fdb85", ++ ... ++ } ++ ``` ++ email: ++ type: [string, "null"] ++ description: | ++ Specification of an email is most often not required, but it is ++ supported. ++ ++ imagePullSecrets: ++ type: array ++ description: | ++ Chart wide configuration to _append_ k8s Secret references to all its ++ pod's `spec.imagePullSecrets` configuration. ++ ++ This will not override or get overridden by pod specific configuration, ++ but instead augment the pod specific configuration. ++ ++ You can use both the k8s native syntax, where each list element is like ++ `{"name": "my-secret-name"}`, or you can let list elements be strings ++ naming the secrets directly. ++ ++ hub: ++ type: object ++ additionalProperties: false ++ required: [baseUrl] ++ properties: ++ revisionHistoryLimit: &revisionHistoryLimit ++ type: [integer, "null"] ++ minimum: 0 ++ description: | ++ Configures the resource's `spec.revisionHistoryLimit`. This is ++ available for Deployment, StatefulSet, and DaemonSet resources. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#revision-history-limit) ++ for more info. ++ config: ++ type: object ++ additionalProperties: true ++ description: | ++ JupyterHub and its components (authenticators, spawners, etc), are ++ Python classes that expose its configuration through ++ [_traitlets_](https://traitlets.readthedocs.io/en/stable/). With this ++ Helm chart configuration (`hub.config`), you can directly configure ++ the Python classes through _static_ YAML values. To _dynamically_ set ++ values, you need to use [`hub.extraConfig`](schema_hub.extraConfig) ++ instead. ++ ++ ```{admonition} Currently intended only for auth config ++ :class: warning ++ This config _currently_ (0.11.0) only influence the software in the ++ `hub` Pod, but some Helm chart config options such as ++ [`hub.baseUrl`](schema_hub.baseUrl) is used to set ++ `JupyterHub.base_url` in the `hub` Pod _and_ influence how other Helm ++ templates are rendered. ++ ++ As we have not yet mapped out all the potential configuration ++ conflicts except for the authentication related configuration options, ++ please accept that using it for something else at this point can lead ++ to issues. ++ ``` ++ ++ __Example__ ++ ++ If you inspect documentation or some `jupyterhub_config.py` to contain ++ the following section: ++ ++ ```python ++ c.JupyterHub.admin_access = true ++ c.JupyterHub.admin_users = ["jovyan1", "jovyan2"] ++ c.KubeSpawner.k8s_api_request_timeout = 10 ++ c.GitHubOAuthenticator.allowed_organizations = ["jupyterhub"] ++ ``` ++ ++ Then, you would be able to represent it with this configuration like: ++ ++ ```yaml ++ hub: ++ config: ++ JupyterHub: ++ admin_access: true ++ admin_users: ++ - jovyan1 ++ - jovyan2 ++ KubeSpawner: ++ k8s_api_request_timeout: 10 ++ GitHubOAuthenticator: ++ allowed_organizations: ++ - jupyterhub ++ ``` ++ ++ ```{admonition} YAML limitations ++ :class: tip ++ You can't represent Python `Bytes` or `Set` objects in YAML directly. ++ ``` ++ ++ ```{admonition} Helm value merging ++ :class: tip ++ `helm` merges a Helm chart's default values with values passed with ++ the `--values` or `-f` flag. During merging, lists are replaced while ++ dictionaries are updated. ++ ``` ++ extraFiles: &extraFiles ++ type: object ++ additionalProperties: false ++ description: | ++ A dictionary with extra files to be injected into the pod's container ++ on startup. This can for example be used to inject: configuration ++ files, custom user interface templates, images, and more. ++ ++ ```yaml ++ # NOTE: "hub" is used in this example, but the configuration is the ++ # same for "singleuser". ++ hub: ++ extraFiles: ++ # The file key is just a reference that doesn't influence the ++ # actual file name. ++ : ++ # mountPath is required and must be the absolute file path. ++ mountPath: ++ ++ # Choose one out of the three ways to represent the actual file ++ # content: data, stringData, or binaryData. ++ # ++ # data should be set to a mapping (dictionary). It will in the ++ # end be rendered to either YAML, JSON, or TOML based on the ++ # filename extension that are required to be either .yaml, .yml, ++ # .json, or .toml. ++ # ++ # If your content is YAML, JSON, or TOML, it can make sense to ++ # use data to represent it over stringData as data can be merged ++ # instead of replaced if set partially from separate Helm ++ # configuration files. ++ # ++ # Both stringData and binaryData should be set to a string ++ # representing the content, where binaryData should be the ++ # base64 encoding of the actual file content. ++ # ++ data: ++ myConfig: ++ myMap: ++ number: 123 ++ string: "hi" ++ myList: ++ - 1 ++ - 2 ++ stringData: | ++ hello world! ++ binaryData: aGVsbG8gd29ybGQhCg== ++ ++ # mode is by default 0644 and you can optionally override it ++ # either by octal notation (example: 0400) or decimal notation ++ # (example: 256). ++ mode: ++ ``` ++ ++ **Using --set-file** ++ ++ To avoid embedding entire files in the Helm chart configuration, you ++ can use the `--set-file` flag during `helm upgrade` to set the ++ stringData or binaryData field. ++ ++ ```yaml ++ hub: ++ extraFiles: ++ my_image: ++ mountPath: /usr/local/share/jupyterhub/static/my_image.png ++ ++ # Files in /usr/local/etc/jupyterhub/jupyterhub_config.d are ++ # automatically loaded in alphabetical order of the final file ++ # name when JupyterHub starts. ++ my_config: ++ mountPath: /usr/local/etc/jupyterhub/jupyterhub_config.d/my_jupyterhub_config.py ++ ``` ++ ++ ```bash ++ # --set-file expects a text based file, so you need to base64 encode ++ # it manually first. ++ base64 my_image.png > my_image.png.b64 ++ ++ helm upgrade <...> \ ++ --set-file hub.extraFiles.my_image.binaryData=./my_image.png.b64 \ ++ --set-file hub.extraFiles.my_config.stringData=./my_jupyterhub_config.py ++ ``` ++ ++ **Common uses** ++ ++ 1. **JupyterHub template customization** ++ ++ You can replace the default JupyterHub user interface templates in ++ the hub pod by injecting new ones to ++ `/usr/local/share/jupyterhub/templates`. These can in turn ++ reference custom images injected to ++ `/usr/local/share/jupyterhub/static`. ++ ++ 1. **JupyterHub standalone file config** ++ ++ Instead of embedding JupyterHub python configuration as a string ++ within a YAML file through ++ [`hub.extraConfig`](schema_hub.extraConfig), you can inject a ++ standalone .py file into ++ `/usr/local/etc/jupyterhub/jupyterhub_config.d` that is ++ automatically loaded. ++ ++ 1. **Flexible configuration** ++ ++ By injecting files, you don't have to embed them in a docker image ++ that you have to rebuild. ++ ++ If your configuration file is a YAML/JSON/TOML file, you can also ++ use `data` instead of `stringData` which allow you to set various ++ configuration in separate Helm config files. This can be useful to ++ help dependent charts override only some configuration part of the ++ file, or to allow for the configuration be set through multiple ++ Helm configuration files. ++ ++ **Limitations** ++ ++ 1. File size ++ ++ The files in `hub.extraFiles` and `singleuser.extraFiles` are ++ respectively stored in their own k8s Secret resource. As k8s ++ Secret's are limited, typically to 1MB, you will be limited to a ++ total file size of less than 1MB as there is also base64 encoding ++ that takes place reducing available capacity to 75%. ++ ++ 2. File updates ++ ++ The files that are mounted are only set during container startup. ++ This is [because we use ++ `subPath`](https://kubernetes.io/docs/concepts/storage/volumes/#secret) ++ as is required to avoid replacing the content of the entire ++ directory we mount in. ++ patternProperties: ++ ".*": ++ type: object ++ additionalProperties: false ++ required: [mountPath] ++ oneOf: ++ - required: [data] ++ - required: [stringData] ++ - required: [binaryData] ++ properties: ++ mountPath: ++ type: string ++ data: ++ type: object ++ additionalProperties: true ++ stringData: ++ type: string ++ binaryData: ++ type: string ++ mode: ++ type: number ++ baseUrl: ++ type: string ++ description: | ++ This is the equivalent of c.JupyterHub.base_url, but it is also needed ++ by the Helm chart in general. So, instead of setting ++ c.JupyterHub.base_url, use this configuration. ++ command: ++ type: array ++ description: | ++ A list of strings to be used to replace the JupyterHub image's ++ `ENTRYPOINT` entry. Note that in k8s lingo, the Dockerfile's ++ `ENTRYPOINT` is called `command`. The list of strings will be expanded ++ with Helm's template function `tpl` which can render Helm template ++ logic inside curly braces (`{{... }}`). ++ ++ This could be useful to wrap the invocation of JupyterHub itself in ++ some custom way. ++ ++ For more details, see the [Kubernetes ++ documentation](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/). ++ args: ++ type: array ++ description: | ++ A list of strings to be used to replace the JupyterHub image's `CMD` ++ entry as well as the Helm chart's default way to start JupyterHub. ++ Note that in k8s lingo, the Dockerfile's `CMD` is called `args`. The ++ list of strings will be expanded with Helm's template function `tpl` ++ which can render Helm template logic inside curly braces (`{{... }}`). ++ ++ ```{warning} ++ By replacing the entire configuration file, which is mounted to ++ `/usr/local/etc/jupyterhub/jupyterhub_config.py` by the Helm chart, ++ instead of appending to it with `hub.extraConfig`, you expose your ++ deployment for issues stemming from getting out of sync with the Helm ++ chart's config file. ++ ++ These kind of issues will be significantly harder to debug and ++ diagnose, and can due to this could cause a lot of time expenditure ++ for both the community maintaining the Helm chart as well as yourself, ++ even if this wasn't the reason for the issue. ++ ++ Due to this, we ask that you do your _absolute best to avoid replacing ++ the default provided `jupyterhub_config.py` file. It can often be ++ possible. For example, if your goal is to have a dedicated .py file ++ for more extensive additions that you can syntax highlight and such ++ and feel limited by passing code in `hub.extraConfig` which is part of ++ a YAML file, you can use [this ++ trick](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/issues/1580#issuecomment-707776237) ++ instead. ++ ``` ++ ++ ```yaml ++ hub: ++ args: ++ - "jupyterhub" ++ - "--config" ++ - "/usr/local/etc/jupyterhub/jupyterhub_config.py" ++ - "--debug" ++ - "--upgrade-db" ++ ``` ++ ++ For more details, see the [Kubernetes ++ documentation](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/). ++ cookieSecret: ++ type: [string, "null"] ++ description: | ++ ```{note} ++ As of version 1.0.0 this will automatically be generated and there is ++ no need to set it manually. ++ ++ If you wish to reset a generated key, you can use `kubectl edit` on ++ the k8s Secret typically named `hub` and remove the ++ `hub.config.JupyterHub.cookie_secret` entry in the k8s Secret, then ++ perform a new `helm upgrade`. ++ ``` ++ ++ A 32-byte cryptographically secure randomly generated string used to sign values of ++ secure cookies set by the hub. If unset, jupyterhub will generate one on startup and ++ save it in the file `jupyterhub_cookie_secret` in the `/srv/jupyterhub` directory of ++ the hub container. A value set here will make JupyterHub overwrite any previous file. ++ ++ You do not need to set this at all if you are using the default configuration for ++ storing databases - sqlite on a persistent volume (with `hub.db.type` set to the ++ default `sqlite-pvc`). If you are using an external database, then you must set this ++ value explicitly - or your users will keep getting logged out each time the hub pod ++ restarts. ++ ++ Changing this value will all user logins to be invalidated. If this secret leaks, ++ *immediately* change it to something else, or user data can be compromised ++ ++ ```sh ++ # to generate a value, run ++ openssl rand -hex 32 ++ ``` ++ image: &image-spec ++ type: object ++ additionalProperties: false ++ required: [name, tag] ++ description: | ++ Set custom image name, tag, pullPolicy, or pullSecrets for the pod. ++ properties: ++ name: ++ type: string ++ description: | ++ The name of the image, without the tag. ++ ++ ``` ++ # example name ++ gcr.io/my-project/my-image ++ ``` ++ tag: ++ type: string ++ description: | ++ The tag of the image to pull. This is the value following `:` in ++ complete image specifications. ++ ++ ``` ++ # example tags ++ v1.11.1 ++ zhy270a ++ ``` ++ pullPolicy: ++ enum: [null, "", IfNotPresent, Always, Never] ++ description: | ++ Configures the Pod's `spec.imagePullPolicy`. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/containers/images/#updating-images) ++ for more info. ++ pullSecrets: ++ type: array ++ description: | ++ A list of references to existing Kubernetes Secrets with ++ credentials to pull the image. ++ ++ This Pod's final `imagePullSecrets` k8s specification will be a ++ combination of: ++ ++ 1. This list of k8s Secrets, specific for this pod. ++ 2. The list of k8s Secrets, for use by all pods in the Helm chart, ++ declared in this Helm charts configuration called ++ `imagePullSecrets`. ++ 3. A k8s Secret, for use by all pods in the Helm chart, if ++ conditionally created from image registry credentials provided ++ under `imagePullSecret` if `imagePullSecret.create` is set to ++ true. ++ ++ ```yaml ++ # example - k8s native syntax ++ pullSecrets: ++ - name: my-k8s-secret-with-image-registry-credentials ++ ++ # example - simplified syntax ++ pullSecrets: ++ - my-k8s-secret-with-image-registry-credentials ++ ``` ++ networkPolicy: &networkPolicy-spec ++ type: object ++ additionalProperties: false ++ description: | ++ This configuration regards the creation and configuration of a k8s ++ _NetworkPolicy resource_. ++ properties: ++ enabled: ++ type: boolean ++ description: | ++ Toggle the creation of the NetworkPolicy resource targeting this ++ pod, and by doing so, restricting its communication to only what ++ is explicitly allowed in the NetworkPolicy. ++ ingress: ++ type: array ++ description: | ++ Additional ingress rules to add besides those that are required ++ for core functionality. ++ egress: ++ type: array ++ description: | ++ Additional egress rules to add besides those that are required for ++ core functionality and those added via ++ [`.egressAllowRules`](schema_hub.networkPolicy.egressAllowRules). ++ ++ ```{versionchanged} 2.0.0 ++ The default value changed from providing one very permissive rule ++ allowing all egress to providing no rule. The permissive rule is ++ still provided via ++ [`.egressAllowRules`](schema_hub.networkPolicy.egressAllowRules) ++ set to true though. ++ ``` ++ ++ As an example, below is a configuration that disables the more ++ broadly permissive `.privateIPs` egress allow rule for the hub ++ pod, and instead provides tightly scoped permissions to access a ++ specific k8s local service as identified by pod labels. ++ ++ ```yaml ++ hub: ++ networkPolicy: ++ egressAllowRules: ++ privateIPs: false ++ egress: ++ - to: ++ - podSelector: ++ matchLabels: ++ app: my-k8s-local-service ++ ports: ++ - protocol: TCP ++ port: 5978 ++ ``` ++ egressAllowRules: ++ type: object ++ additionalProperties: false ++ description: | ++ This is a set of predefined rules that when enabled will be added ++ to the NetworkPolicy list of egress rules. ++ ++ The resulting egress rules will be a composition of: ++ - rules specific for the respective pod(s) function within the ++ Helm chart ++ - rules based on enabled `egressAllowRules` flags ++ - rules explicitly specified by the user ++ ++ ```{note} ++ Each flag under this configuration will not render into a ++ dedicated rule in the NetworkPolicy resource, but instead combine ++ with the other flags to a reduced set of rules to avoid a ++ performance penalty. ++ ``` ++ ++ ```{versionadded} 2.0.0 ++ ``` ++ properties: ++ cloudMetadataServer: ++ type: boolean ++ description: | ++ Defaults to `false` for singleuser servers, but to `true` for ++ all other network policies. ++ ++ When enabled this rule allows the respective pod(s) to ++ establish outbound connections to the cloud metadata server. ++ ++ Note that the `nonPrivateIPs` rule is allowing all non Private ++ IP ranges but makes an exception for the cloud metadata ++ server, leaving this as the definitive configuration to allow ++ access to the cloud metadata server. ++ ++ ```{versionchanged} 3.0.0 ++ This configuration is not allowed to be configured true at the ++ same time as ++ [`singleuser.cloudMetadata.blockWithIptables`](schema_singleuser.cloudMetadata.blockWithIptables) ++ to avoid an ambiguous configuration. ++ ``` ++ dnsPortsCloudMetadataServer: ++ type: boolean ++ description: | ++ Defaults to `true` for all network policies. ++ ++ When enabled this rule allows the respective pod(s) to ++ establish outbound connections to the cloud metadata server ++ via port 53. ++ ++ Relying on this rule for the singleuser config should go hand ++ in hand with disabling ++ [`singleuser.cloudMetadata.blockWithIptables`](schema_singleuser.cloudMetadata.blockWithIptables) ++ to avoid an ambiguous configuration. ++ ++ Known situations when this rule can be relevant: ++ ++ - In GKE clusters with Cloud DNS that is reached at the ++ cloud metadata server's non-private IP. ++ ++ ```{note} ++ This chart doesn't know how to identify the DNS server that ++ pods will rely on due to variations between how k8s clusters ++ have been setup. Due to that, multiple rules are enabled by ++ default to ensure DNS connectivity. ++ ``` ++ ++ ```{versionadded} 3.0.0 ++ ``` ++ dnsPortsKubeSystemNamespace: ++ type: boolean ++ description: | ++ Defaults to `true` for all network policies. ++ ++ When enabled this rule allows the respective pod(s) to ++ establish outbound connections to pods in the kube-system ++ namespace via port 53. ++ ++ Known situations when this rule can be relevant: ++ ++ - GKE, EKS, AKS, and other clusters relying directly on ++ `kube-dns` or `coredns` pods in the `kube-system` namespace. ++ ++ ```{note} ++ This chart doesn't know how to identify the DNS server that ++ pods will rely on due to variations between how k8s clusters ++ have been setup. Due to that, multiple rules are enabled by ++ default to ensure DNS connectivity. ++ ``` ++ ++ ```{versionadded} 3.0.0 ++ ``` ++ dnsPortsPrivateIPs: ++ type: boolean ++ description: | ++ Defaults to `true` for all network policies. ++ ++ When enabled this rule allows the respective pod(s) to ++ establish outbound connections to private IPs via port 53. ++ ++ Known situations when this rule can be relevant: ++ ++ - GKE clusters relying on a DNS server indirectly via a a node ++ local DNS cache at an unknown private IP. ++ ++ ```{note} ++ This chart doesn't know how to identify the DNS server that ++ pods will rely on due to variations between how k8s clusters ++ have been setup. Due to that, multiple rules are enabled by ++ default to ensure DNS connectivity. ++ ++ ```{warning} ++ This rule is not expected to work in clusters relying on ++ Cilium to enforce the NetworkPolicy rules (includes GKE ++ clusters with Dataplane v2), this is due to a [known ++ limitation](https://github.com/cilium/cilium/issues/9209). ++ ``` ++ nonPrivateIPs: ++ type: boolean ++ description: | ++ Defaults to `true` for all network policies. ++ ++ When enabled this rule allows the respective pod(s) to ++ establish outbound connections to the non-private IP ranges ++ with the exception of the cloud metadata server. This means ++ respective pod(s) can establish connections to the internet ++ but not (say) an unsecured prometheus server running in the ++ same cluster. ++ privateIPs: ++ type: boolean ++ description: | ++ Defaults to `false` for singleuser servers, but to `true` for ++ all other network policies. ++ ++ Private IPs refer to the IP ranges `10.0.0.0/8`, ++ `172.16.0.0/12`, `192.168.0.0/16`. ++ ++ When enabled this rule allows the respective pod(s) to ++ establish outbound connections to the internal k8s cluster. ++ This means users can access the internet but not (say) an ++ unsecured prometheus server running in the same cluster. ++ ++ Since not all workloads in the k8s cluster may have ++ NetworkPolicies setup to restrict their incoming connections, ++ having this set to false can be a good defense against ++ malicious intent from someone in control of software in these ++ pods. ++ ++ If possible, try to avoid setting this to true as it gives ++ broad permissions that could be specified more directly via ++ the [`.egress`](schema_singleuser.networkPolicy.egress). ++ ++ ```{warning} ++ This rule is not expected to work in clusters relying on ++ Cilium to enforce the NetworkPolicy rules (includes GKE ++ clusters with Dataplane v2), this is due to a [known ++ limitation](https://github.com/cilium/cilium/issues/9209). ++ ``` ++ interNamespaceAccessLabels: ++ enum: [accept, ignore] ++ description: | ++ This configuration option determines if both namespaces and pods ++ in other namespaces, that have specific access labels, should be ++ accepted to allow ingress (set to `accept`), or, if the labels are ++ to be ignored when applied outside the local namespace (set to ++ `ignore`). ++ ++ The available access labels for respective NetworkPolicy resources ++ are: ++ ++ - `hub.jupyter.org/network-access-hub: "true"` (hub) ++ - `hub.jupyter.org/network-access-proxy-http: "true"` (proxy.chp, proxy.traefik) ++ - `hub.jupyter.org/network-access-proxy-api: "true"` (proxy.chp) ++ - `hub.jupyter.org/network-access-singleuser: "true"` (singleuser) ++ allowedIngressPorts: ++ type: array ++ description: | ++ A rule to allow ingress on these ports will be added no matter ++ what the origin of the request is. The default setting for ++ `proxy.chp` and `proxy.traefik`'s networkPolicy configuration is ++ `[http, https]`, while it is `[]` for other networkPolicies. ++ ++ Note that these port names or numbers target a Pod's port name or ++ number, not a k8s Service's port name or number. ++ db: ++ type: object ++ additionalProperties: false ++ properties: ++ type: ++ enum: [sqlite-pvc, sqlite-memory, mysql, postgres, other] ++ description: | ++ Type of database backend to use for the hub database. ++ ++ The Hub requires a persistent database to function, and this lets you specify ++ where it should be stored. ++ ++ The various options are: ++ ++ 1. **sqlite-pvc** ++ ++ Use an `sqlite` database kept on a persistent volume attached to the hub. ++ ++ By default, this disk is created by the cloud provider using ++ *dynamic provisioning* configured by a [storage ++ class](https://kubernetes.io/docs/concepts/storage/storage-classes/). ++ You can customize how this disk is created / attached by ++ setting various properties under `hub.db.pvc`. ++ ++ This is the default setting, and should work well for most cloud provider ++ deployments. ++ ++ 2. **sqlite-memory** ++ ++ Use an in-memory `sqlite` database. This should only be used for testing, ++ since the database is erased whenever the hub pod restarts - causing the hub ++ to lose all memory of users who had logged in before. ++ ++ When using this for testing, make sure you delete all other objects that the ++ hub has created (such as user pods, user PVCs, etc) every time the hub restarts. ++ Otherwise you might run into errors about duplicate resources. ++ ++ 3. **mysql** ++ ++ Use an externally hosted mysql database. ++ ++ You have to specify an sqlalchemy connection string for the mysql database you ++ want to connect to in `hub.db.url` if using this option. ++ ++ The general format of the connection string is: ++ ``` ++ mysql+pymysql://:@:/ ++ ``` ++ ++ The user specified in the connection string must have the rights to create ++ tables in the database specified. ++ ++ 4. **postgres** ++ ++ Use an externally hosted postgres database. ++ ++ You have to specify an sqlalchemy connection string for the postgres database you ++ want to connect to in `hub.db.url` if using this option. ++ ++ The general format of the connection string is: ++ ``` ++ postgresql+psycopg2://:@:/ ++ ``` ++ ++ The user specified in the connection string must have the rights to create ++ tables in the database specified. ++ ++ 5. **other** ++ ++ Use an externally hosted database of some kind other than mysql ++ or postgres. ++ ++ When using _other_, the database password must be passed as ++ part of [hub.db.url](schema_hub.db.url) as ++ [hub.db.password](schema_hub.db.password) will be ignored. ++ pvc: ++ type: object ++ additionalProperties: false ++ required: [storage] ++ description: | ++ Customize the Persistent Volume Claim used when `hub.db.type` is `sqlite-pvc`. ++ properties: ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: &labels-and-annotations-patternProperties ++ ".*": ++ type: string ++ description: | ++ Annotations to apply to the PVC containing the sqlite database. ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) ++ for more details about annotations. ++ selector: ++ type: object ++ additionalProperties: true ++ description: | ++ Label selectors to set for the PVC containing the sqlite database. ++ ++ Useful when you are using a specific PV, and want to bind to ++ that and only that. ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) ++ for more details about using a label selector for what PV to ++ bind to. ++ storage: ++ type: string ++ description: | ++ Size of disk to request for the database disk. ++ accessModes: ++ type: array ++ items: ++ type: [string, "null"] ++ description: | ++ AccessModes contains the desired access modes the volume ++ should have. See [the k8s ++ documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1) ++ for more information. ++ storageClassName: ++ type: [string, "null"] ++ description: | ++ Name of the StorageClass required by the claim. ++ ++ If this is a blank string it will be set to a blank string, ++ while if it is null, it will not be set at all. ++ subPath: ++ type: [string, "null"] ++ description: | ++ Path within the volume from which the container's volume ++ should be mounted. Defaults to "" (volume's root). ++ upgrade: ++ type: [boolean, "null"] ++ description: | ++ Users with external databases need to opt-in for upgrades of the ++ JupyterHub specific database schema if needed as part of a ++ JupyterHub version upgrade. ++ url: ++ type: [string, "null"] ++ description: | ++ Connection string when `hub.db.type` is mysql or postgres. ++ ++ See documentation for `hub.db.type` for more details on the format of this property. ++ password: ++ type: [string, "null"] ++ description: | ++ Password for the database when `hub.db.type` is mysql or postgres. ++ labels: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Extra labels to add to the hub pod. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) ++ to learn more about labels. ++ initContainers: ++ type: array ++ description: | ++ list of initContainers to be run with hub pod. See [Kubernetes Docs](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) ++ ++ ```yaml ++ hub: ++ initContainers: ++ - name: init-myservice ++ image: busybox:1.28 ++ command: ['sh', '-c', 'command1'] ++ - name: init-mydb ++ image: busybox:1.28 ++ command: ['sh', '-c', 'command2'] ++ ``` ++ extraEnv: ++ type: [object, array] ++ additionalProperties: true ++ description: | ++ Extra environment variables that should be set for the hub pod. ++ ++ Environment variables are usually used to: ++ - Pass parameters to some custom code in `hub.extraConfig`. ++ - Configure code running in the hub pod, such as an authenticator or ++ spawner. ++ ++ String literals with `$(ENV_VAR_NAME)` will be expanded by Kubelet which ++ is a part of Kubernetes. ++ ++ ```yaml ++ hub: ++ extraEnv: ++ # basic notation (for literal values only) ++ MY_ENV_VARS_NAME1: "my env var value 1" ++ ++ # explicit notation (the "name" field takes precedence) ++ HUB_NAMESPACE: ++ name: HUB_NAMESPACE ++ valueFrom: ++ fieldRef: ++ fieldPath: metadata.namespace ++ ++ # implicit notation (the "name" field is implied) ++ PREFIXED_HUB_NAMESPACE: ++ value: "my-prefix-$(HUB_NAMESPACE)" ++ SECRET_VALUE: ++ valueFrom: ++ secretKeyRef: ++ name: my-k8s-secret ++ key: password ++ ``` ++ ++ For more information, see the [Kubernetes EnvVar ++ specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#envvar-v1-core). ++ extraConfig: ++ type: object ++ additionalProperties: true ++ description: | ++ Arbitrary extra python based configuration that should be in `jupyterhub_config.py`. ++ ++ This is the *escape hatch* - if you want to configure JupyterHub to do something specific ++ that is not present here as an option, you can write the raw Python to do it here. ++ ++ extraConfig is a *dict*, so there can be multiple configuration ++ snippets under different names. The configuration sections are run in ++ alphabetical order based on the keys. ++ ++ Non-exhaustive examples of things you can do here: ++ - Subclass authenticator / spawner to do a custom thing ++ - Dynamically launch different images for different sets of images ++ - Inject an auth token from GitHub authenticator into user pod ++ - Anything else you can think of! ++ ++ Since this is usually a multi-line string, you want to format it using YAML's ++ [| operator](https://yaml.org/spec/1.2.2/#23-scalars). ++ ++ For example: ++ ++ ```yaml ++ hub: ++ extraConfig: ++ myConfig.py: | ++ c.JupyterHub.something = 'something' ++ c.Spawner.something_else = 'something else' ++ ``` ++ ++ ```{note} ++ No code validation is performed until JupyterHub loads it! If you make ++ a typo here, it will probably manifest itself as the hub pod failing ++ to start up and instead entering an `Error` state or the subsequent ++ `CrashLoopBackoff` state. ++ ++ To make use of your own programs linters etc, it would be useful to ++ not embed Python code inside a YAML file. To do that, consider using ++ [`hub.extraFiles`](schema_hub.extraFiles) and mounting a file to ++ `/usr/local/etc/jupyterhub/jupyterhub_config.d` in order to load your ++ extra configuration logic. ++ ``` ++ ++ fsGid: ++ type: [integer, "null"] ++ minimum: 0 ++ # This schema entry is needed to help us print a more helpful error ++ # message in NOTES.txt if hub.fsGid is set. ++ # ++ description: | ++ ```{note} ++ Removed in version 2.0.0. Use ++ [`hub.podSecurityContext`](schema_hub.podSecurityContext) and specify ++ `fsGroup` instead. ++ ``` ++ service: ++ type: object ++ additionalProperties: false ++ description: | ++ Object to configure the service the JupyterHub will be exposed on by the Kubernetes server. ++ properties: ++ type: ++ enum: [ClusterIP, NodePort, LoadBalancer, ExternalName] ++ description: | ++ The Kubernetes ServiceType to be used. ++ ++ The default type is `ClusterIP`. ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) ++ to learn more about service types. ++ ports: ++ type: object ++ additionalProperties: false ++ description: | ++ Object to configure the ports the hub service will be deployed on. ++ properties: ++ nodePort: ++ type: [integer, "null"] ++ minimum: 0 ++ description: | ++ The nodePort to deploy the hub service on. ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Kubernetes annotations to apply to the hub service. ++ extraPorts: ++ type: array ++ description: | ++ Extra ports to add to the Hub Service object besides `hub` / `8081`. ++ This should be an array that includes `name`, `port`, and `targetPort`. ++ See [Multi-port Services](https://kubernetes.io/docs/concepts/services-networking/service/#multi-port-services) for more details. ++ loadBalancerIP: ++ type: [string, "null"] ++ description: | ++ A public IP address the hub Kubernetes service should be exposed ++ on. To expose the hub directly is not recommended. Instead route ++ traffic through the proxy-public service towards the hub. ++ ++ pdb: &pdb-spec ++ type: object ++ additionalProperties: false ++ description: | ++ Configure a PodDisruptionBudget for this Deployment. ++ ++ These are disabled by default for our deployments that don't support ++ being run in parallel with multiple replicas. Only the user-scheduler ++ currently supports being run in parallel with multiple replicas. If ++ they are enabled for a Deployment with only one replica, they will ++ block `kubectl drain` of a node for example. ++ ++ Note that if you aim to block scaling down a node with the ++ hub/proxy/autohttps pod that would cause disruptions of the ++ deployment, then you should instead annotate the pods of the ++ Deployment [as described ++ here](https://github.com/kubernetes/autoscaler/blob/HEAD/cluster-autoscaler/FAQ.md#what-types-of-pods-can-prevent-ca-from-removing-a-node). ++ ++ "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/) ++ for more details about disruptions. ++ properties: ++ enabled: ++ type: boolean ++ description: | ++ Decides if a PodDisruptionBudget is created targeting the ++ Deployment's pods. ++ maxUnavailable: ++ type: [integer, "null"] ++ description: | ++ The maximum number of pods that can be unavailable during ++ voluntary disruptions. ++ minAvailable: ++ type: [integer, "null"] ++ description: | ++ The minimum number of pods required to be available during ++ voluntary disruptions. ++ existingSecret: ++ type: [string, "null"] ++ description: | ++ This option allow you to provide the name of an existing k8s Secret to ++ use alongside of the chart managed k8s Secret. The content of this k8s ++ Secret will be merged with the chart managed k8s Secret, giving ++ priority to the self-managed k8s Secret. ++ ++ ```{warning} ++ 1. The self managed k8s Secret must mirror the structure in the chart ++ managed secret. ++ 2. [`proxy.secretToken`](schema_proxy.secretToken) (aka. ++ `hub.config.ConfigurableHTTPProxy.auth_token`) is only read from ++ the chart managed k8s Secret. ++ ``` ++ nodeSelector: &nodeSelector-spec ++ type: object ++ additionalProperties: true ++ description: | ++ An object with key value pairs representing labels. K8s Nodes are ++ required to have match all these labels for this Pod to scheduled on ++ them. ++ ++ ```yaml ++ disktype: ssd ++ nodetype: awesome ++ ``` ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) ++ for more details. ++ tolerations: &tolerations-spec ++ type: array ++ description: | ++ Tolerations allow a pod to be scheduled on nodes with taints. These ++ tolerations are additional tolerations to the tolerations common to ++ all pods of a their respective kind ++ ([scheduling.corePods.tolerations](schema_scheduling.corePods.tolerations), ++ [scheduling.userPods.tolerations](schema_scheduling.userPods.tolerations)). ++ ++ Pass this field an array of ++ [`Toleration`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#toleration-v1-core) ++ objects. ++ ++ See the [Kubernetes ++ docs](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) ++ for more info. ++ activeServerLimit: ++ type: [integer, "null"] ++ description: &jupyterhub-native-config-description | ++ JupyterHub native configuration, see the [JupyterHub ++ documentation](https://jupyterhub.readthedocs.io/en/stable/reference/api/app.html) ++ for more information. ++ allowNamedServers: ++ type: [boolean, "null"] ++ description: *jupyterhub-native-config-description ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ K8s annotations for the hub pod. ++ authenticatePrometheus: ++ type: [boolean, "null"] ++ description: *jupyterhub-native-config-description ++ concurrentSpawnLimit: ++ type: [integer, "null"] ++ description: *jupyterhub-native-config-description ++ consecutiveFailureLimit: ++ type: [integer, "null"] ++ description: *jupyterhub-native-config-description ++ podSecurityContext: &podSecurityContext-spec ++ additionalProperties: true ++ description: | ++ A k8s native specification of the pod's security context, see [the ++ documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core) ++ for details. ++ containerSecurityContext: &containerSecurityContext-spec ++ type: object ++ additionalProperties: true ++ description: | ++ A k8s native specification of the container's security context, see [the ++ documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core) ++ for details. ++ deploymentStrategy: ++ type: object ++ additionalProperties: false ++ properties: ++ rollingUpdate: ++ type: [string, "null"] ++ type: ++ type: [string, "null"] ++ description: | ++ JupyterHub does not support running in parallel, due to this we ++ default to using a deployment strategy of Recreate. ++ extraContainers: &extraContainers-spec ++ type: array ++ description: | ++ Additional containers for the Pod. Use a k8s native syntax. ++ extraVolumeMounts: &extraVolumeMounts-spec ++ type: array ++ description: | ++ Additional volume mounts for the Container. Use a k8s native syntax. ++ extraVolumes: &extraVolumes-spec ++ type: array ++ description: | ++ Additional volumes for the Pod. Use a k8s native syntax. ++ livenessProbe: &probe-spec ++ type: object ++ additionalProperties: true ++ required: [enabled] ++ if: ++ properties: ++ enabled: ++ const: true ++ then: ++ description: | ++ This config option is like the k8s native specification of a ++ container probe, except that it also supports an `enabled` boolean ++ flag. ++ ++ See [the k8s ++ documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#probe-v1-core) ++ for more details. ++ readinessProbe: *probe-spec ++ namedServerLimitPerUser: ++ type: [integer, "null"] ++ description: *jupyterhub-native-config-description ++ redirectToServer: ++ type: [boolean, "null"] ++ description: *jupyterhub-native-config-description ++ resources: &resources-spec ++ type: object ++ additionalProperties: true ++ description: | ++ A k8s native specification of resources, see [the ++ documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#resourcerequirements-v1-core). ++ lifecycle: &lifecycle-spec ++ type: object ++ additionalProperties: false ++ description: | ++ A k8s native specification of lifecycle hooks on the container, see [the ++ documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#lifecycle-v1-core). ++ properties: ++ postStart: ++ type: object ++ additionalProperties: true ++ preStop: ++ type: object ++ additionalProperties: true ++ services: ++ type: object ++ additionalProperties: true ++ description: | ++ This is where you register JupyterHub services. For details on how to ++ configure these services in this Helm chart just keep reading but for ++ details on services themselves instead read [JupyterHub's ++ documentation](https://jupyterhub.readthedocs.io/en/stable/reference/api/service.html). ++ ++ ```{note} ++ Only a selection of JupyterHub's configuration options that can be ++ configured for a service are documented below. All configuration set ++ here will be applied even if this Helm chart doesn't recognize it. ++ ``` ++ ++ JupyterHub's native configuration accepts a list of service objects, ++ this Helm chart only accept a dictionary where each key represents the ++ name of a service and the value is the actual service objects. ++ ++ When configuring JupyterHub services via this Helm chart, the `name` ++ field can be omitted as it can be implied by the dictionary key. ++ Further, the `api_token` field can be omitted as it will be ++ automatically generated as of version 1.1.0 of this Helm chart. ++ ++ If you have an external service that needs to access the automatically ++ generated api_token for the service, you can access it from the `hub` ++ k8s Secret part of this Helm chart under the key ++ `hub.services.my-service-config-key.apiToken`. ++ ++ Here is an example configuration of two services where the first ++ explicitly sets a name and api_token, while the second omits those and ++ lets the name be implied from the key name and the api_token be ++ automatically generated. ++ ++ ```yaml ++ hub: ++ services: ++ my-service-1: ++ admin: true ++ name: my-explicitly-set-service-name ++ api_token: my-explicitly-set-api_token ++ ++ # the name of the following service will be my-service-2 ++ # the api_token of the following service will be generated ++ my-service-2: {} ++ ``` ++ ++ If you develop a Helm chart depending on the JupyterHub Helm chart and ++ want to let some Pod's environment variable be populated with the ++ api_token of a service registered like above, then do something along ++ these lines. ++ ++ ```yaml ++ # ... container specification of a pod ... ++ env: ++ - name: MY_SERVICE_1_API_TOKEN ++ valueFrom: ++ secretKeyRef: ++ # Don't hardcode the name, use the globally accessible ++ # named templates part of the JupyterHub Helm chart. ++ name: {{ include "jupyterhub.hub.fullname" . }} ++ # Note below the use of the configuration key my-service-1 ++ # rather than the explicitly set service name. ++ key: hub.services.my-service-1.apiToken ++ ``` ++ properties: ++ name: ++ type: string ++ description: | ++ The name can be implied via the key name under which this ++ service is configured, and is due to that allowed to be ++ omitted in this Helm chart configuration of JupyterHub. ++ admin: ++ type: boolean ++ command: ++ type: [string, array] ++ url: ++ type: string ++ api_token: ++ type: [string, "null"] ++ description: | ++ The api_token will be automatically generated if not ++ explicitly set. It will also be exposed in via a k8s Secret ++ part of this Helm chart under a specific key. ++ ++ See the documentation under ++ [`hub.services`](schema_hub.services) for details about this. ++ apiToken: ++ type: [string, "null"] ++ description: | ++ An alias for api_token provided for backward compatibility by ++ the JupyterHub Helm chart that will be transformed to ++ api_token. ++ loadRoles: ++ type: object ++ additionalProperties: true ++ description: | ++ This is where you should define JupyterHub roles and apply them to ++ JupyterHub users, groups, and services to grant them additional ++ permissions as defined in JupyterHub's RBAC system. ++ ++ Complement this documentation with [JupyterHub's ++ documentation](https://jupyterhub.readthedocs.io/en/stable/rbac/roles.html#defining-roles) ++ about `load_roles`. ++ ++ Note that while JupyterHub's native configuration `load_roles` accepts ++ a list of role objects, this Helm chart only accepts a dictionary where ++ each key represents the name of a role and the value is the actual ++ role object. ++ ++ ```yaml ++ hub: ++ loadRoles: ++ teacher: ++ description: Access to users' information and group membership ++ ++ # this role provides permissions to... ++ scopes: [users, groups] ++ ++ # this role will be assigned to... ++ users: [erik] ++ services: [grading-service] ++ groups: [teachers] ++ ``` ++ ++ When configuring JupyterHub roles via this Helm chart, the `name` ++ field can be omitted as it can be implied by the dictionary key. ++ shutdownOnLogout: ++ type: [boolean, "null"] ++ description: *jupyterhub-native-config-description ++ templatePaths: ++ type: array ++ description: *jupyterhub-native-config-description ++ templateVars: ++ type: object ++ additionalProperties: true ++ description: *jupyterhub-native-config-description ++ serviceAccount: &serviceAccount ++ type: object ++ required: [create] ++ additionalProperties: false ++ description: | ++ Configuration for a k8s ServiceAccount dedicated for use by the ++ specific pod which this configuration is nested under. ++ properties: ++ create: ++ type: boolean ++ description: | ++ Whether or not to create the `ServiceAccount` resource. ++ name: ++ type: ["string", "null"] ++ description: | ++ This configuration serves multiple purposes: ++ ++ - It will be the `serviceAccountName` referenced by related Pods. ++ - If `create` is set, the created ServiceAccount resource will be named like this. ++ - If [`rbac.create`](schema_rbac.create) is set, the associated (Cluster)RoleBindings will bind to this name. ++ ++ If not explicitly provided, a default name will be used. ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Kubernetes annotations to apply to the k8s ServiceAccount. ++ extraPodSpec: &extraPodSpec-spec ++ type: object ++ additionalProperties: true ++ description: | ++ Arbitrary extra k8s pod specification as a YAML object. The default ++ value of this setting is an empty object, i.e. no extra configuration. ++ The value of this property is augmented to the pod specification as-is. ++ ++ This is a powerful tool for expert k8s administrators with advanced ++ configuration requirements. This setting should only be used for ++ configuration that cannot be accomplished through the other settings. ++ Misusing this setting can break your deployment and/or compromise ++ your system security. ++ ++ This is one of four related settings for inserting arbitrary pod ++ specification: ++ ++ 1. hub.extraPodSpec ++ 2. proxy.chp.extraPodSpec ++ 3. proxy.traefik.extraPodSpec ++ 4. scheduling.userScheduler.extraPodSpec ++ ++ One real-world use of these settings is to enable host networking. For ++ example, to configure host networking for the hub pod, add the ++ following to your helm configuration values: ++ ++ ```yaml ++ hub: ++ extraPodSpec: ++ hostNetwork: true ++ dnsPolicy: ClusterFirstWithHostNet ++ ``` ++ ++ Likewise, to configure host networking for the proxy pod, add the ++ following: ++ ++ ```yaml ++ proxy: ++ chp: ++ extraPodSpec: ++ hostNetwork: true ++ dnsPolicy: ClusterFirstWithHostNet ++ ``` ++ ++ N.B. Host networking has special security implications and can easily ++ break your deployment. This is an example—not an endorsement. ++ ++ See [PodSpec](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec) ++ for the latest pod resource specification. ++ ++ proxy: ++ type: object ++ additionalProperties: false ++ properties: ++ chp: ++ type: object ++ additionalProperties: false ++ description: | ++ Configure the configurable-http-proxy (chp) pod managed by jupyterhub to route traffic ++ both to itself and to user pods. ++ properties: ++ revisionHistoryLimit: *revisionHistoryLimit ++ networkPolicy: *networkPolicy-spec ++ extraCommandLineFlags: ++ type: array ++ description: | ++ A list of strings to be added as command line options when ++ starting ++ [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy#command-line-options) ++ that will be expanded with Helm's template function `tpl` which ++ can render Helm template logic inside curly braces (`{{ ... }}`). ++ ++ ```yaml ++ proxy: ++ chp: ++ extraCommandLineFlags: ++ - "--auto-rewrite" ++ - "--custom-header {{ .Values.myCustomStuff }}" ++ ``` ++ ++ Note that these will be appended last, and if you provide the same ++ flag twice, the last flag will be used, which mean you can ++ override the default flag values as well. ++ extraEnv: ++ type: [object, array] ++ additionalProperties: true ++ description: | ++ Extra environment variables that should be set for the chp pod. ++ ++ Environment variables are usually used here to: ++ - override HUB_SERVICE_PORT or HUB_SERVICE_HOST default values ++ - set CONFIGPROXY_SSL_KEY_PASSPHRASE for setting passphrase of SSL keys ++ ++ String literals with `$(ENV_VAR_NAME)` will be expanded by Kubelet which ++ is a part of Kubernetes. ++ ++ ```yaml ++ proxy: ++ chp: ++ extraEnv: ++ # basic notation (for literal values only) ++ MY_ENV_VARS_NAME1: "my env var value 1" ++ ++ # explicit notation (the "name" field takes precedence) ++ CHP_NAMESPACE: ++ name: CHP_NAMESPACE ++ valueFrom: ++ fieldRef: ++ fieldPath: metadata.namespace ++ ++ # implicit notation (the "name" field is implied) ++ PREFIXED_CHP_NAMESPACE: ++ value: "my-prefix-$(CHP_NAMESPACE)" ++ SECRET_VALUE: ++ valueFrom: ++ secretKeyRef: ++ name: my-k8s-secret ++ key: password ++ ``` ++ ++ For more information, see the [Kubernetes EnvVar ++ specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#envvar-v1-core). ++ pdb: *pdb-spec ++ nodeSelector: *nodeSelector-spec ++ tolerations: *tolerations-spec ++ containerSecurityContext: *containerSecurityContext-spec ++ image: *image-spec ++ livenessProbe: *probe-spec ++ readinessProbe: *probe-spec ++ resources: *resources-spec ++ defaultTarget: ++ type: [string, "null"] ++ description: | ++ Override the URL for the default routing target for the proxy. ++ Defaults to JupyterHub itself. ++ This will generally only have an effect while JupyterHub is not running, ++ as JupyterHub adds itself as the default target after it starts. ++ errorTarget: ++ type: [string, "null"] ++ description: | ++ Override the URL for the error target for the proxy. ++ Defaults to JupyterHub itself. ++ Useful to reduce load on the Hub ++ or produce more informative error messages than the Hub's default, ++ e.g. in highly customized deployments such as BinderHub. ++ See Configurable HTTP Proxy for details on implementing an error target. ++ extraPodSpec: *extraPodSpec-spec ++ secretToken: ++ type: [string, "null"] ++ description: | ++ ```{note} ++ As of version 1.0.0 this will automatically be generated and there is ++ no need to set it manually. ++ ++ If you wish to reset a generated key, you can use `kubectl edit` on ++ the k8s Secret typically named `hub` and remove the ++ `hub.config.ConfigurableHTTPProxy.auth_token` entry in the k8s Secret, ++ then perform a new `helm upgrade`. ++ ``` ++ ++ A 32-byte cryptographically secure randomly generated string used to ++ secure communications between the hub pod and the proxy pod running a ++ [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy) ++ instance. ++ ++ ```sh ++ # to generate a value, run ++ openssl rand -hex 32 ++ ``` ++ ++ Changing this value will cause the proxy and hub pods to restart. It is good security ++ practice to rotate these values over time. If this secret leaks, *immediately* change ++ it to something else, or user data can be compromised. ++ service: ++ type: object ++ additionalProperties: false ++ description: | ++ Configuration of the k8s Service `proxy-public` which either will ++ point to the `autohttps` pod running Traefik for TLS termination, or ++ the `proxy` pod running ConfigurableHTTPProxy. Incoming traffic from ++ users on the internet should always go through this k8s Service. ++ ++ When this service targets the `autohttps` pod which then routes to the ++ `proxy` pod, a k8s Service named `proxy-http` will be added targeting ++ the `proxy` pod and only accepting HTTP traffic on port 80. ++ properties: ++ type: ++ enum: [ClusterIP, NodePort, LoadBalancer, ExternalName] ++ description: | ++ Default `LoadBalancer`. ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) ++ to learn more about service types. ++ labels: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Extra labels to add to the proxy service. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) ++ to learn more about labels. ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Annotations to apply to the service that is exposing the proxy. ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) ++ for more details about annotations. ++ nodePorts: ++ type: object ++ additionalProperties: false ++ description: | ++ Object to set NodePorts to expose the service on for http and https. ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport) ++ for more details about NodePorts. ++ properties: ++ http: ++ type: [integer, "null"] ++ description: | ++ The HTTP port the proxy-public service should be exposed on. ++ https: ++ type: [integer, "null"] ++ description: | ++ The HTTPS port the proxy-public service should be exposed on. ++ disableHttpPort: ++ type: boolean ++ description: | ++ Default `false`. ++ ++ If `true`, port 80 for incoming HTTP traffic will no longer be exposed. This should not be used with `proxy.https.type=letsencrypt` or `proxy.https.enabled=false` as it would remove the only exposed port. ++ extraPorts: ++ type: array ++ description: | ++ Extra ports the k8s Service should accept incoming traffic on, ++ which will be redirected to either the `autohttps` pod (treafik) ++ or the `proxy` pod (chp). ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#serviceport-v1-core) ++ for the structure of the items in this list. ++ loadBalancerIP: ++ type: [string, "null"] ++ description: | ++ The public IP address the proxy-public Kubernetes service should ++ be exposed on. This entry will end up at the configurable proxy ++ server that JupyterHub manages, which will direct traffic to user ++ pods at the `/user` path and the hub pod at the `/hub` path. ++ ++ Set this if you want to use a fixed external IP address instead of ++ a dynamically acquired one. This is relevant if you have a domain ++ name that you want to point to a specific IP and want to ensure it ++ doesn't change. ++ loadBalancerSourceRanges: ++ type: array ++ description: | ++ A list of IP CIDR ranges that are allowed to access the load balancer service. ++ Defaults to allowing everyone to access it. ++ https: ++ type: object ++ additionalProperties: false ++ description: | ++ Object for customizing the settings for HTTPS used by the JupyterHub's proxy. ++ For more information on configuring HTTPS for your JupyterHub, see the [HTTPS section in our security guide](https) ++ properties: ++ enabled: ++ type: [boolean, "null"] ++ description: | ++ Indicator to set whether HTTPS should be enabled or not on the proxy. Defaults to `true` if the https object is provided. ++ type: ++ enum: [null, "", letsencrypt, manual, offload, secret] ++ description: | ++ The type of HTTPS encryption that is used. ++ Decides on which ports and network policies are used for communication via HTTPS. Setting this to `secret` sets the type to manual HTTPS with a secret that has to be provided in the `https.secret` object. ++ Defaults to `letsencrypt`. ++ letsencrypt: ++ type: object ++ additionalProperties: false ++ properties: ++ contactEmail: ++ type: [string, "null"] ++ description: | ++ The contact email to be used for automatically provisioned HTTPS certificates by Let's Encrypt. For more information see [Set up automatic HTTPS](setup-automatic-https). ++ Required for automatic HTTPS. ++ acmeServer: ++ type: [string, "null"] ++ description: | ++ Let's Encrypt is one of various ACME servers that can provide ++ a certificate, and by default their production server is used. ++ ++ Let's Encrypt staging: https://acme-staging-v02.api.letsencrypt.org/directory ++ Let's Encrypt production: acmeServer: https://acme-v02.api.letsencrypt.org/directory ++ manual: ++ type: object ++ additionalProperties: false ++ description: | ++ Object for providing own certificates for manual HTTPS configuration. To be provided when setting `https.type` to `manual`. ++ See [Set up manual HTTPS](setup-manual-https) ++ properties: ++ key: ++ type: [string, "null"] ++ description: | ++ The RSA private key to be used for HTTPS. ++ To be provided in the form of ++ ++ ``` ++ key: | ++ -----BEGIN RSA PRIVATE KEY----- ++ ... ++ -----END RSA PRIVATE KEY----- ++ ``` ++ cert: ++ type: [string, "null"] ++ description: | ++ The certificate to be used for HTTPS. ++ To be provided in the form of ++ ++ ``` ++ cert: | ++ -----BEGIN CERTIFICATE----- ++ ... ++ -----END CERTIFICATE----- ++ ``` ++ secret: ++ type: object ++ additionalProperties: false ++ description: | ++ Secret to be provided when setting `https.type` to `secret`. ++ properties: ++ name: ++ type: [string, "null"] ++ description: | ++ Name of the secret ++ key: ++ type: [string, "null"] ++ description: | ++ Path to the private key to be used for HTTPS. ++ Example: `'tls.key'` ++ crt: ++ type: [string, "null"] ++ description: | ++ Path to the certificate to be used for HTTPS. ++ Example: `'tls.crt'` ++ hosts: ++ type: array ++ description: | ++ You domain in list form. ++ Required for automatic HTTPS. See [Set up automatic HTTPS](setup-automatic-https). ++ To be provided like: ++ ``` ++ hosts: ++ - ++ ``` ++ traefik: ++ type: object ++ additionalProperties: false ++ description: | ++ Configure the traefik proxy used to terminate TLS when 'autohttps' is enabled ++ properties: ++ revisionHistoryLimit: *revisionHistoryLimit ++ labels: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Extra labels to add to the traefik pod. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) ++ to learn more about labels. ++ networkPolicy: *networkPolicy-spec ++ extraInitContainers: ++ type: array ++ description: | ++ list of extraInitContainers to be run with traefik pod, after the containers set in the chart. See [Kubernetes Docs](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) ++ ++ ```yaml ++ proxy: ++ traefik: ++ extraInitContainers: ++ - name: init-myservice ++ image: busybox:1.28 ++ command: ['sh', '-c', 'command1'] ++ - name: init-mydb ++ image: busybox:1.28 ++ command: ['sh', '-c', 'command2'] ++ ``` ++ extraEnv: ++ type: [object, array] ++ additionalProperties: true ++ description: | ++ Extra environment variables that should be set for the traefik pod. ++ ++ Environment Variables here may be used to configure traefik. ++ ++ String literals with `$(ENV_VAR_NAME)` will be expanded by Kubelet which ++ is a part of Kubernetes. ++ ++ ```yaml ++ proxy: ++ traefik: ++ extraEnv: ++ # basic notation (for literal values only) ++ MY_ENV_VARS_NAME1: "my env var value 1" ++ ++ # explicit notation (the "name" field takes precedence) ++ TRAEFIK_NAMESPACE: ++ name: TRAEFIK_NAMESPACE ++ valueFrom: ++ fieldRef: ++ fieldPath: metadata.namespace ++ ++ # implicit notation (the "name" field is implied) ++ PREFIXED_TRAEFIK_NAMESPACE: ++ value: "my-prefix-$(TRAEFIK_NAMESPACE)" ++ SECRET_VALUE: ++ valueFrom: ++ secretKeyRef: ++ name: my-k8s-secret ++ key: password ++ ``` ++ ++ For more information, see the [Kubernetes EnvVar ++ specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#envvar-v1-core). ++ pdb: *pdb-spec ++ nodeSelector: *nodeSelector-spec ++ tolerations: *tolerations-spec ++ containerSecurityContext: *containerSecurityContext-spec ++ extraDynamicConfig: ++ type: object ++ additionalProperties: true ++ description: | ++ This refers to traefik's post-startup configuration. ++ ++ This Helm chart already provide such configuration, so this is a ++ place where you can merge in additional configuration. If you are ++ about to use this configuration, you may want to inspect the ++ default configuration declared ++ [here](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/HEAD/jupyterhub/templates/proxy/autohttps/_configmap-dynamic.yaml). ++ extraPorts: ++ type: array ++ description: | ++ Extra ports for the traefik container within the autohttps pod ++ that you would like to expose, formatted in a k8s native way. ++ extraStaticConfig: ++ type: object ++ additionalProperties: true ++ description: | ++ This refers to traefik's startup configuration. ++ ++ This Helm chart already provide such configuration, so this is a ++ place where you can merge in additional configuration. If you are ++ about to use this configuration, you may want to inspect the ++ default configuration declared ++ [here](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/HEAD/jupyterhub/templates/proxy/autohttps/_configmap-traefik.yaml). ++ extraVolumes: *extraVolumes-spec ++ extraVolumeMounts: *extraVolumeMounts-spec ++ hsts: ++ type: object ++ additionalProperties: false ++ required: [includeSubdomains, maxAge, preload] ++ description: | ++ This section regards a HTTP Strict-Transport-Security (HSTS) ++ response header. It can act as a request for a visiting web ++ browsers to enforce HTTPS on their end in for a given time into ++ the future, and optionally also for future requests to subdomains. ++ ++ These settings relate to traefik configuration which we use as a ++ TLS termination proxy. ++ ++ See [Mozilla's ++ documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) ++ for more information. ++ properties: ++ includeSubdomains: ++ type: boolean ++ maxAge: ++ type: integer ++ preload: ++ type: boolean ++ image: *image-spec ++ resources: *resources-spec ++ serviceAccount: *serviceAccount ++ extraPodSpec: *extraPodSpec-spec ++ labels: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ K8s labels for the proxy pod. ++ ++ ```{note} ++ For consistency, this should really be located under ++ proxy.chp.labels but isn't for historical reasons. ++ ``` ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ K8s annotations for the proxy pod. ++ ++ ```{note} ++ For consistency, this should really be located under ++ proxy.chp.annotations but isn't for historical reasons. ++ ``` ++ deploymentStrategy: ++ type: object ++ additionalProperties: false ++ properties: ++ rollingUpdate: ++ type: [string, "null"] ++ type: ++ type: [string, "null"] ++ description: | ++ While the proxy pod running ++ [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy) ++ could run in parallel, two instances running in parallel wouldn't ++ both receive updates from JupyterHub regarding how it should route ++ traffic. Due to this we default to using a deployment strategy of ++ Recreate instead of RollingUpdate. ++ secretSync: ++ type: object ++ additionalProperties: false ++ description: | ++ This configuration section refers to configuration of the sidecar ++ container in the autohttps pod running next to its traefik container ++ responsible for TLS termination. ++ ++ The purpose of this container is to store away and load TLS ++ certificates from a k8s Secret. The TLS certificates are acquired by ++ the ACME client (LEGO) that is running within the traefik container, ++ where traefik is using them for TLS termination. ++ properties: ++ containerSecurityContext: *containerSecurityContext-spec ++ image: *image-spec ++ resources: *resources-spec ++ ++ singleuser: ++ type: object ++ additionalProperties: false ++ description: | ++ Options for customizing the environment that is provided to the users after they log in. ++ properties: ++ networkPolicy: *networkPolicy-spec ++ podNameTemplate: ++ type: [string, "null"] ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.pod_name_template](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.pod_name_template). ++ cpu: ++ type: object ++ additionalProperties: false ++ description: | ++ Set CPU limits & guarantees that are enforced for each user. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) ++ for more info. ++ properties: ++ limit: ++ type: [number, "null"] ++ guarantee: ++ type: [number, "null"] ++ memory: ++ type: object ++ additionalProperties: false ++ description: | ++ Set Memory limits & guarantees that are enforced for each user. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) ++ for more info. ++ properties: ++ limit: ++ type: [number, string, "null"] ++ guarantee: ++ type: [number, string, "null"] ++ description: | ++ Note that this field is referred to as *requests* by the Kubernetes API. ++ image: *image-spec ++ initContainers: ++ type: array ++ description: | ++ list of initContainers to be run every singleuser pod. See [Kubernetes Docs](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) ++ ++ ```yaml ++ singleuser: ++ initContainers: ++ - name: init-myservice ++ image: busybox:1.28 ++ command: ['sh', '-c', 'command1'] ++ - name: init-mydb ++ image: busybox:1.28 ++ command: ['sh', '-c', 'command2'] ++ ``` ++ profileList: ++ type: array ++ description: | ++ For more information about the profile list, see [KubeSpawner's ++ documentation](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner) ++ as this is simply a passthrough to that configuration. ++ ++ ```{note} ++ The image-pullers are aware of the overrides of images in ++ `singleuser.profileList` but they won't be if you configure it in ++ JupyterHub's configuration of '`c.KubeSpawner.profile_list`. ++ ``` ++ ++ ```yaml ++ singleuser: ++ profileList: ++ - display_name: "Default: Shared, 8 CPU cores" ++ description: "Your code will run on a shared machine with CPU only." ++ default: True ++ - display_name: "Personal, 4 CPU cores & 26GB RAM, 1 NVIDIA Tesla K80 GPU" ++ description: "Your code will run a personal machine with a GPU." ++ kubespawner_override: ++ extra_resource_limits: ++ nvidia.com/gpu: "1" ++ ``` ++ extraFiles: *extraFiles ++ extraEnv: ++ type: [object, array] ++ additionalProperties: true ++ description: | ++ Extra environment variables that should be set for the user pods. ++ ++ String literals with `$(ENV_VAR_NAME)` will be expanded by Kubelet which ++ is a part of Kubernetes. Note that the user pods will already have ++ access to a set of environment variables that you can use, like ++ `JUPYTERHUB_USER` and `JUPYTERHUB_HOST`. For more information about these ++ inspect [this source ++ code](https://github.com/jupyterhub/jupyterhub/blob/cc8e7806530466dce8968567d1bbd2b39a7afa26/jupyterhub/spawner.py#L763). ++ ++ ```yaml ++ singleuser: ++ extraEnv: ++ # basic notation (for literal values only) ++ MY_ENV_VARS_NAME1: "my env var value 1" ++ ++ # explicit notation (the "name" field takes precedence) ++ USER_NAMESPACE: ++ name: USER_NAMESPACE ++ valueFrom: ++ fieldRef: ++ fieldPath: metadata.namespace ++ ++ # implicit notation (the "name" field is implied) ++ PREFIXED_USER_NAMESPACE: ++ value: "my-prefix-$(USER_NAMESPACE)" ++ SECRET_VALUE: ++ valueFrom: ++ secretKeyRef: ++ name: my-k8s-secret ++ key: password ++ ``` ++ ++ For more information, see the [Kubernetes EnvVar ++ specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#envvar-v1-core). ++ nodeSelector: *nodeSelector-spec ++ extraTolerations: *tolerations-spec ++ extraNodeAffinity: ++ type: object ++ additionalProperties: false ++ description: | ++ Affinities describe where pods prefer or require to be scheduled, they ++ may prefer or require a node where they are to be scheduled to have a ++ certain label (node affinity). They may also require to be scheduled ++ in proximity or with a lack of proximity to another pod (pod affinity ++ and anti pod affinity). ++ ++ See the [Kubernetes ++ docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) ++ for more info. ++ properties: ++ required: ++ type: array ++ description: | ++ Pass this field an array of ++ [`NodeSelectorTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#nodeselectorterm-v1-core) ++ objects. ++ preferred: ++ type: array ++ description: | ++ Pass this field an array of ++ [`PreferredSchedulingTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#preferredschedulingterm-v1-core) ++ objects. ++ extraPodAffinity: ++ type: object ++ additionalProperties: false ++ description: | ++ See the description of `singleuser.extraNodeAffinity`. ++ properties: ++ required: ++ type: array ++ description: | ++ Pass this field an array of ++ [`PodAffinityTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podaffinityterm-v1-core) ++ objects. ++ preferred: ++ type: array ++ description: | ++ Pass this field an array of ++ [`WeightedPodAffinityTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#weightedpodaffinityterm-v1-core) ++ objects. ++ extraPodAntiAffinity: ++ type: object ++ additionalProperties: false ++ description: | ++ See the description of `singleuser.extraNodeAffinity`. ++ properties: ++ required: ++ type: array ++ description: | ++ Pass this field an array of ++ [`PodAffinityTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podaffinityterm-v1-core) ++ objects. ++ preferred: ++ type: array ++ description: | ++ Pass this field an array of ++ [`WeightedPodAffinityTerm`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#weightedpodaffinityterm-v1-core) ++ objects. ++ cloudMetadata: ++ type: object ++ additionalProperties: false ++ required: [blockWithIptables, ip] ++ description: | ++ Please refer to dedicated section in [the Helm chart ++ documentation](block-metadata-iptables) for more information about ++ this. ++ properties: ++ blockWithIptables: ++ type: boolean ++ ip: ++ type: string ++ ++ cmd: ++ type: [array, string, "null"] ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.cmd](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.cmd). ++ The default is "jupyterhub-singleuser". ++ Use `cmd: null` to launch a custom CMD from the image, ++ which must launch jupyterhub-singleuser or an equivalent process eventually. ++ For example: Jupyter's docker-stacks images. ++ defaultUrl: ++ type: [string, "null"] ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.default_url](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.default_url). ++ # FIXME: name mismatch, named events_enabled in kubespawner ++ events: ++ type: [boolean, "null"] ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.events_enabled](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.events_enabled). ++ extraAnnotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.extra_annotations](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_annotations). ++ extraContainers: ++ type: array ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.extra_containers](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_containers). ++ extraLabels: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.extra_labels](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_labels). ++ extraPodConfig: ++ type: object ++ additionalProperties: true ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.extra_pod_config](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_pod_config). ++ extraResource: ++ type: object ++ additionalProperties: false ++ properties: ++ # FIXME: name mismatch, named extra_resource_guarantees in kubespawner ++ guarantees: ++ type: object ++ additionalProperties: true ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.extra_resource_guarantees](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_resource_guarantees). ++ # FIXME: name mismatch, named extra_resource_limits in kubespawner ++ limits: ++ type: object ++ additionalProperties: true ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.extra_resource_limits](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_resource_limits). ++ fsGid: ++ type: [integer, "null"] ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.fs_gid](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.fs_gid). ++ lifecycleHooks: ++ type: object ++ additionalProperties: false ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.lifecycle_hooks](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.lifecycle_hooks). ++ properties: ++ postStart: ++ type: object ++ additionalProperties: true ++ preStop: ++ type: object ++ additionalProperties: true ++ networkTools: ++ type: object ++ additionalProperties: false ++ description: | ++ This configuration section refers to configuration of a conditionally ++ created initContainer for the user pods with a purpose to block a ++ specific IP address. ++ ++ This initContainer will be created if ++ [`singleuser.cloudMetadata.blockWithIptables`](schema_singleuser.cloudMetadata.blockWithIptables) ++ is set to true. ++ properties: ++ image: *image-spec ++ resources: *resources-spec ++ # FIXME: name mismatch, named service_account in kubespawner ++ serviceAccountName: ++ type: [string, "null"] ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.service_account](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.service_account). ++ startTimeout: ++ type: [integer, "null"] ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.start_timeout](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.start_timeout). ++ storage: ++ type: object ++ additionalProperties: false ++ required: [type, homeMountPath] ++ description: | ++ This section configures KubeSpawner directly to some extent but also ++ indirectly through Helm chart specific configuration options such as ++ [`singleuser.storage.type`](schema_singleuser.storage.type). ++ properties: ++ capacity: ++ type: [string, "null"] ++ description: | ++ Configures `KubeSpawner.storage_capacity`. ++ ++ See the [KubeSpawner ++ documentation](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html) ++ for more information. ++ dynamic: ++ type: object ++ additionalProperties: false ++ properties: ++ pvcNameTemplate: ++ type: [string, "null"] ++ description: | ++ Configures `KubeSpawner.pvc_name_template` which will be the ++ resource name of the PVC created by KubeSpawner for each user ++ if needed. ++ storageAccessModes: ++ type: array ++ items: ++ type: [string, "null"] ++ description: | ++ Configures `KubeSpawner.storage_access_modes`. ++ ++ See KubeSpawners documentation and [the k8s ++ documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes) ++ for more information. ++ storageClass: ++ type: [string, "null"] ++ description: | ++ Configures `KubeSpawner.storage_class`, which can be an ++ explicit StorageClass to dynamically provision storage for the ++ PVC that KubeSpawner will create. ++ ++ There is of a default StorageClass available in k8s clusters ++ for use if this is unspecified. ++ volumeNameTemplate: ++ type: [string, "null"] ++ description: | ++ Configures `KubeSpawner.volume_name_template`, which is the ++ name to reference from the containers volumeMounts section. ++ extraLabels: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Configures `KubeSpawner.storage_extra_labels`. Note that these ++ labels are set on the PVC during creation only and won't be ++ updated after creation. ++ extraVolumeMounts: *extraVolumeMounts-spec ++ extraVolumes: *extraVolumes-spec ++ homeMountPath: ++ type: string ++ description: | ++ The location within the container where the home folder storage ++ should be mounted. ++ static: ++ type: object ++ additionalProperties: false ++ properties: ++ pvcName: ++ type: [string, "null"] ++ description: | ++ Configures `KubeSpawner.pvc_claim_name` to reference ++ pre-existing storage. ++ subPath: ++ type: [string, "null"] ++ description: | ++ Configures the `subPath` field of a ++ `KubeSpawner.volume_mounts` entry added by the Helm chart. ++ ++ Path within the volume from which the container's volume ++ should be mounted. ++ type: ++ enum: [dynamic, static, none] ++ description: | ++ Decide if you want storage to be provisioned dynamically ++ (dynamic), or if you want to attach existing storage (static), or ++ don't want any storage to be attached (none). ++ allowPrivilegeEscalation: ++ type: [boolean, "null"] ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.allow_privilege_escalation](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.allow_privilege_escalation). ++ uid: ++ type: [integer, "null"] ++ description: | ++ Passthrough configuration for ++ [KubeSpawner.uid](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.uid). ++ ++ This dictates as what user the main container will start up as. ++ ++ As an example of when this is needed, consider if you want to enable ++ sudo rights for some of your users. This can be done by starting up as ++ root, enabling it from the container in a startup script, and then ++ transitioning to the normal user. ++ ++ Default is 1000, set to null to use the container's default. ++ ++ scheduling: ++ type: object ++ additionalProperties: false ++ description: | ++ Objects for customizing the scheduling of various pods on the nodes and ++ related labels. ++ properties: ++ userScheduler: ++ type: object ++ additionalProperties: false ++ required: [enabled, plugins, pluginConfig, logLevel] ++ description: | ++ The user scheduler is making sure that user pods are scheduled ++ tight on nodes, this is useful for autoscaling of user node pools. ++ properties: ++ enabled: ++ type: boolean ++ description: | ++ Enables the user scheduler. ++ revisionHistoryLimit: *revisionHistoryLimit ++ replicas: ++ type: integer ++ description: | ++ You can have multiple schedulers to share the workload or improve ++ availability on node failure. ++ image: *image-spec ++ pdb: *pdb-spec ++ nodeSelector: *nodeSelector-spec ++ tolerations: *tolerations-spec ++ labels: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Extra labels to add to the userScheduler pods. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) ++ to learn more about labels. ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Extra annotations to add to the user-scheduler pods. ++ containerSecurityContext: *containerSecurityContext-spec ++ logLevel: ++ type: integer ++ description: | ++ Corresponds to the verbosity level of logging made by the ++ kube-scheduler binary running within the user-scheduler pod. ++ plugins: ++ type: object ++ additionalProperties: true ++ description: | ++ These plugins refers to kube-scheduler plugins as documented ++ [here](https://kubernetes.io/docs/reference/scheduling/config/). ++ ++ The user-scheduler is really just a kube-scheduler configured in a ++ way to pack users tight on nodes using these plugins. See ++ values.yaml for information about the default plugins. ++ pluginConfig: ++ type: array ++ description: | ++ Individually activated plugins can be configured further. ++ resources: *resources-spec ++ serviceAccount: *serviceAccount ++ extraPodSpec: *extraPodSpec-spec ++ podPriority: ++ type: object ++ additionalProperties: false ++ description: | ++ Pod Priority is used to allow real users evict user placeholder pods ++ that in turn by entering a Pending state can trigger a scale up by a ++ cluster autoscaler. ++ ++ Having this option enabled only make sense if the following conditions ++ are met: ++ ++ 1. A cluster autoscaler is installed. ++ 2. user-placeholer pods are configured to have a priority equal or ++ higher than the cluster autoscaler's "priority cutoff" so that the ++ cluster autoscaler scales up a node in advance for a pending user ++ placeholder pod. ++ 3. Normal user pods have a higher priority than the user-placeholder ++ pods. ++ 4. Image puller pods have a priority between normal user pods and ++ user-placeholder pods. ++ ++ Note that if the default priority cutoff if not configured on cluster ++ autoscaler, it will currently default to 0, and that in the future ++ this is meant to be lowered. If your cloud provider is installing the ++ cluster autoscaler for you, they may also configure this specifically. ++ ++ Recommended settings for a cluster autoscaler... ++ ++ ... with a priority cutoff of -10 (GKE): ++ ++ ```yaml ++ podPriority: ++ enabled: true ++ globalDefault: false ++ defaultPriority: 0 ++ imagePullerPriority: -5 ++ userPlaceholderPriority: -10 ++ ``` ++ ++ ... with a priority cutoff of 0: ++ ++ ```yaml ++ podPriority: ++ enabled: true ++ globalDefault: true ++ defaultPriority: 10 ++ imagePullerPriority: 5 ++ userPlaceholderPriority: 0 ++ ``` ++ properties: ++ enabled: ++ type: boolean ++ globalDefault: ++ type: boolean ++ description: | ++ Warning! This will influence all pods in the cluster. ++ ++ The priority a pod usually get is 0. But this can be overridden ++ with a PriorityClass resource if it is declared to be the global ++ default. This configuration option allows for the creation of such ++ global default. ++ defaultPriority: ++ type: integer ++ description: | ++ The actual value for the default pod priority. ++ imagePullerPriority: ++ type: integer ++ description: | ++ The actual value for the [hook|continuous]-image-puller pods' priority. ++ userPlaceholderPriority: ++ type: integer ++ description: | ++ The actual value for the user-placeholder pods' priority. ++ userPlaceholder: ++ type: object ++ additionalProperties: false ++ description: | ++ User placeholders simulate users but will thanks to PodPriority be ++ evicted by the cluster autoscaler if a real user shows up. In this way ++ placeholders allow you to create a headroom for the real users and ++ reduce the risk of a user having to wait for a node to be added. Be ++ sure to use the the continuous image puller as well along with ++ placeholders, so the images are also available when real users arrive. ++ ++ To test your setup efficiently, you can adjust the amount of user ++ placeholders with the following command: ++ ```sh ++ # Configure to have 3 user placeholders ++ kubectl scale sts/user-placeholder --replicas=3 ++ ``` ++ properties: ++ enabled: ++ type: boolean ++ image: *image-spec ++ revisionHistoryLimit: *revisionHistoryLimit ++ replicas: ++ type: integer ++ description: | ++ How many placeholder pods would you like to have? ++ labels: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Extra labels to add to the userPlaceholder pods. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) ++ to learn more about labels. ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Extra annotations to add to the placeholder pods. ++ resources: ++ type: object ++ additionalProperties: true ++ description: | ++ Unless specified here, the placeholder pods will request the same ++ resources specified for the real singleuser pods. ++ containerSecurityContext: *containerSecurityContext-spec ++ corePods: ++ type: object ++ additionalProperties: false ++ description: | ++ These settings influence the core pods like the hub, proxy and ++ user-scheduler pods. ++ These settings influence all pods considered core pods, namely: ++ ++ - hub ++ - proxy ++ - autohttps ++ - hook-image-awaiter ++ - user-scheduler ++ ++ By defaults, the tolerations are: ++ ++ - hub.jupyter.org/dedicated=core:NoSchedule ++ - hub.jupyter.org_dedicated=core:NoSchedule ++ ++ Note that tolerations set here are combined with the respective ++ components dedicated tolerations, and that `_` is available in case ++ `/` isn't allowed in the clouds tolerations. ++ properties: ++ tolerations: *tolerations-spec ++ nodeAffinity: ++ type: object ++ additionalProperties: false ++ description: | ++ Where should pods be scheduled? Perhaps on nodes with a certain ++ label is preferred or even required? ++ properties: ++ matchNodePurpose: ++ enum: [ignore, prefer, require] ++ description: | ++ Decide if core pods *ignore*, *prefer* or *require* to ++ schedule on nodes with this label: ++ ``` ++ hub.jupyter.org/node-purpose=core ++ ``` ++ userPods: ++ type: object ++ additionalProperties: false ++ description: | ++ These settings influence all pods considered user pods, namely: ++ ++ - user-placeholder ++ - hook-image-puller ++ - continuous-image-puller ++ - jupyter- ++ ++ By defaults, the tolerations are: ++ ++ - hub.jupyter.org/dedicated=core:NoSchedule ++ - hub.jupyter.org_dedicated=core:NoSchedule ++ ++ Note that tolerations set here are combined with the respective ++ components dedicated tolerations, and that `_` is available in case ++ `/` isn't allowed in the clouds tolerations. ++ properties: ++ tolerations: *tolerations-spec ++ nodeAffinity: ++ type: object ++ additionalProperties: false ++ description: | ++ Where should pods be scheduled? Perhaps on nodes with a certain ++ label is preferred or even required? ++ properties: ++ matchNodePurpose: ++ enum: [ignore, prefer, require] ++ description: | ++ Decide if user pods *ignore*, *prefer* or *require* to ++ schedule on nodes with this label: ++ ``` ++ hub.jupyter.org/node-purpose=user ++ ``` ++ ++ ingress: ++ type: object ++ additionalProperties: false ++ required: [enabled] ++ properties: ++ enabled: ++ type: boolean ++ description: | ++ Enable the creation of a Kubernetes Ingress to proxy-public service. ++ ++ See [Advanced Topics — Zero to JupyterHub with Kubernetes ++ 0.7.0 documentation](ingress) ++ for more details. ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Annotations to apply to the Ingress resource. ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) ++ for more details about annotations. ++ ingressClassName: ++ type: [string, "null"] ++ description: | ++ Maps directly to the Ingress resource's `spec.ingressClassName``. ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) ++ for more details. ++ hosts: ++ type: array ++ description: | ++ List of hosts to route requests to the proxy. ++ pathSuffix: ++ type: [string, "null"] ++ description: | ++ Suffix added to Ingress's routing path pattern. ++ ++ Specify `*` if your ingress matches path by glob pattern. ++ pathType: ++ enum: [Prefix, Exact, ImplementationSpecific] ++ description: | ++ The path type to use. The default value is 'Prefix'. ++ ++ See [the Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types) ++ for more details about path types. ++ tls: ++ type: array ++ description: | ++ TLS configurations for Ingress. ++ ++ See [the Kubernetes ++ documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) ++ for more details about annotations. ++ ++ prePuller: ++ type: object ++ additionalProperties: false ++ required: [hook, continuous] ++ properties: ++ revisionHistoryLimit: *revisionHistoryLimit ++ labels: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Extra labels to add to the pre puller job pods. ++ ++ See the [Kubernetes docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) ++ to learn more about labels. ++ annotations: ++ type: object ++ additionalProperties: false ++ patternProperties: *labels-and-annotations-patternProperties ++ description: | ++ Annotations to apply to the hook and continous image puller pods. One example use case is to ++ disable istio sidecars which could interfere with the image pulling. ++ resources: ++ type: object ++ additionalProperties: true ++ description: | ++ These are standard Kubernetes resources with requests and limits for ++ cpu and memory. They will be used on the containers in the pods ++ pulling images. These should be set extremely low as the containers ++ shut down directly or is a pause container that just idles. ++ ++ They were made configurable as usage of ResourceQuota may require ++ containers in the namespace to have explicit resources set. ++ extraTolerations: *tolerations-spec ++ hook: ++ type: object ++ additionalProperties: false ++ required: [enabled] ++ description: | ++ See the [*optimization ++ section*](pulling-images-before-users-arrive) ++ for more details. ++ properties: ++ enabled: ++ type: boolean ++ pullOnlyOnChanges: ++ type: boolean ++ description: | ++ Pull only if changes have been made to the images to pull, or more ++ accurately if the hook-image-puller daemonset has changed in any ++ way. ++ podSchedulingWaitDuration: ++ description: | ++ The `hook-image-awaiter` has a criteria to await all the ++ `hook-image-puller` DaemonSet's pods to both schedule and finish ++ their image pulling. This flag can be used to relax this criteria ++ to instead only await the pods that _has already scheduled_ to ++ finish image pulling after a certain duration. ++ ++ The value of this is that sometimes the newly created ++ `hook-image-puller` pods cannot be scheduled because nodes are ++ full, and then it probably won't make sense to block a `helm ++ upgrade`. ++ ++ An infinite duration to wait for pods to schedule can be ++ represented by `-1`. This was the default behavior of version ++ 0.9.0 and earlier. ++ type: integer ++ nodeSelector: *nodeSelector-spec ++ tolerations: *tolerations-spec ++ containerSecurityContext: *containerSecurityContext-spec ++ image: *image-spec ++ resources: *resources-spec ++ serviceAccount: *serviceAccount ++ continuous: ++ type: object ++ additionalProperties: false ++ required: [enabled] ++ description: | ++ See the [*optimization ++ section*](pulling-images-before-users-arrive) ++ for more details. ++ ++ ```{note} ++ If used with a Cluster Autoscaler (an autoscaling node pool), also add ++ user-placeholders and enable pod priority. ++ ``` ++ properties: ++ enabled: ++ type: boolean ++ pullProfileListImages: ++ type: boolean ++ description: | ++ The singleuser.profileList configuration can provide a selection of ++ images. This option determines if all images identified there should ++ be pulled, both by the hook and continuous pullers. ++ ++ Images are looked for under `kubespawner_override`, and also ++ `profile_options.choices.kubespawner_override` since version 3.2.0. ++ ++ The reason to disable this, is that if you have for example 10 images ++ which start pulling in order from 1 to 10, a user that arrives and ++ wants to start a pod with image number 10 will need to wait for all ++ images to be pulled, and then it may be preferable to just let the ++ user arriving wait for a single image to be pulled on arrival. ++ extraImages: ++ type: object ++ additionalProperties: false ++ description: | ++ See the [*optimization section*](images-that-will-be-pulled) for more ++ details. ++ ++ ```yaml ++ prePuller: ++ extraImages: ++ my-extra-image-i-want-pulled: ++ name: jupyter/all-spark-notebook ++ tag: 2343e33dec46 ++ ``` ++ patternProperties: ++ ".*": ++ type: object ++ additionalProperties: false ++ required: [name, tag] ++ properties: ++ name: ++ type: string ++ tag: ++ type: string ++ containerSecurityContext: *containerSecurityContext-spec ++ pause: ++ type: object ++ additionalProperties: false ++ description: | ++ The image-puller pods rely on initContainer to pull all images, and ++ their actual container when they are done is just running a `pause` ++ container. These are settings for that pause container. ++ properties: ++ containerSecurityContext: *containerSecurityContext-spec ++ image: *image-spec ++ ++ custom: ++ type: object ++ additionalProperties: true ++ description: | ++ Additional values to pass to the Hub. ++ JupyterHub will not itself look at these, ++ but you can read values in your own custom config via `hub.extraConfig`. ++ For example: ++ ++ ```yaml ++ custom: ++ myHost: "https://example.horse" ++ hub: ++ extraConfig: ++ myConfig.py: | ++ c.MyAuthenticator.host = get_config("custom.myHost") ++ ``` ++ ++ cull: ++ type: object ++ additionalProperties: false ++ required: [enabled] ++ description: | ++ The ++ [jupyterhub-idle-culler](https://github.com/jupyterhub/jupyterhub-idle-culler) ++ can run as a JupyterHub managed service to _cull_ running servers. ++ properties: ++ enabled: ++ type: boolean ++ description: | ++ Enable/disable use of jupyter-idle-culler. ++ users: ++ type: [boolean, "null"] ++ description: See the `--cull-users` flag. ++ adminUsers: ++ type: [boolean, "null"] ++ description: See the `--cull-admin-users` flag. ++ removeNamedServers: ++ type: [boolean, "null"] ++ description: See the `--remove-named-servers` flag. ++ timeout: ++ type: [integer, "null"] ++ description: See the `--timeout` flag. ++ every: ++ type: [integer, "null"] ++ description: See the `--cull-every` flag. ++ concurrency: ++ type: [integer, "null"] ++ description: See the `--concurrency` flag. ++ maxAge: ++ type: [integer, "null"] ++ description: See the `--max-age` flag. ++ ++ debug: ++ type: object ++ additionalProperties: false ++ required: [enabled] ++ properties: ++ enabled: ++ type: boolean ++ description: | ++ Increases the loglevel throughout the resources in the Helm chart. ++ ++ rbac: ++ type: object ++ additionalProperties: false ++ required: [create] ++ properties: ++ enabled: ++ type: boolean ++ # This schema entry is needed to help us print a more helpful error ++ # message in NOTES.txt if hub.fsGid is set. ++ # ++ description: | ++ ````{note} ++ Removed in version 2.0.0. If you have been using `rbac.enable=false` ++ (strongly discouraged), then the equivalent configuration would be: ++ ++ ```yaml ++ rbac: ++ create: false ++ hub: ++ serviceAccount: ++ create: false ++ proxy: ++ traefik: ++ serviceAccount: ++ create: false ++ scheduling: ++ userScheduler: ++ serviceAccount: ++ create: false ++ prePuller: ++ hook: ++ serviceAccount: ++ create: false ++ ``` ++ ```` ++ create: ++ type: boolean ++ description: | ++ Decides if (Cluster)Role and (Cluster)RoleBinding resources are ++ created and bound to the configured serviceAccounts. ++ ++ global: ++ type: object ++ additionalProperties: true ++ properties: ++ safeToShowValues: ++ type: boolean ++ description: | ++ A flag that should only be set to true temporarily when experiencing a ++ deprecation message that contain censored content that you wish to ++ reveal. +diff --git a/applications/jupyterhub/deploy/values.yaml b/applications/jupyterhub/deploy/values.yaml +index 2f5cbca..41e108d 100755 +--- a/applications/jupyterhub/deploy/values.yaml ++++ b/applications/jupyterhub/deploy/values.yaml +@@ -1,4 +1,4 @@ +-harness: ++harness: # EDIT: CLOUDHARNESS + subdomain: hub + service: + auto: false +@@ -31,6 +31,11 @@ harness: + fullnameOverride: "" + nameOverride: + ++# enabled is ignored by the jupyterhub chart itself, but a chart depending on ++# the jupyterhub chart conditionally can make use this config option as the ++# condition. ++enabled: ++ + # custom can contain anything you want to pass to the hub pod, as all passed + # Helm template values will be made available there. + custom: {} +@@ -54,10 +59,11 @@ imagePullSecrets: [] + # ConfigurableHTTPProxy speaks with the actual ConfigurableHTTPProxy server in + # the proxy pod. + hub: ++ revisionHistoryLimit: + config: + JupyterHub: + admin_access: true +- authenticator_class: keycloak ++ authenticator_class: keycloak # EDIT: CLOUDHARNESS + service: + type: ClusterIP + annotations: {} +@@ -68,7 +74,6 @@ hub: + baseUrl: / + cookieSecret: + initContainers: [] +- fsGid: 1000 + nodeSelector: {} + tolerations: [] + concurrentSpawnLimit: 64 +@@ -106,37 +111,38 @@ hub: + extraVolumes: [] + extraVolumeMounts: [] + image: +- name: jupyterhub/k8s-hub +- tag: "1.1.3" ++ name: quay.io/jupyterhub/k8s-hub ++ tag: "3.2.1" + pullPolicy: + pullSecrets: [] + resources: {} ++ podSecurityContext: ++ fsGroup: 1000 + containerSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + allowPrivilegeEscalation: false + lifecycle: {} ++ loadRoles: {} + services: {} + pdb: + enabled: false + maxUnavailable: + minAvailable: 1 + networkPolicy: +- enabled: false ++ enabled: true + ingress: [] +- ## egress for JupyterHub already includes Kubernetes internal DNS and +- ## access to the proxy, but can be restricted further, but ensure to allow +- ## access to the Kubernetes API server that couldn't be pinned ahead of +- ## time. +- ## +- ## ref: https://stackoverflow.com/a/59016417/2220152 +- egress: +- - to: +- - ipBlock: +- cidr: 0.0.0.0/0 ++ egress: [] ++ egressAllowRules: ++ cloudMetadataServer: true ++ dnsPortsCloudMetadataServer: true ++ dnsPortsKubeSystemNamespace: true ++ dnsPortsPrivateIPs: true ++ nonPrivateIPs: true ++ privateIPs: true + interNamespaceAccessLabels: ignore + allowedIngressPorts: [] +- allowNamedServers: true ++ allowNamedServers: true # EDIT: CLOUDHARNESS + namedServerLimitPerUser: + authenticatePrometheus: + redirectToServer: +@@ -163,11 +169,13 @@ hub: + timeoutSeconds: 1 + existingSecret: + serviceAccount: ++ create: true ++ name: + annotations: {} + extraPodSpec: {} + + rbac: +- enabled: true ++ create: true + + # proxy relates to the proxy pod, the proxy-public service, and the autohttps + # pod and proxy-http service. +@@ -202,7 +210,7 @@ proxy: + rollingUpdate: + # service relates to the proxy-public service + service: +- type: NodePort ++ type: NodePort # EDIT: CLOUDHARNESS + labels: {} + annotations: {} + nodePorts: +@@ -215,13 +223,17 @@ proxy: + # chp relates to the proxy pod, which is responsible for routing traffic based + # on dynamic configuration sent from JupyterHub to CHP's REST API. + chp: ++ revisionHistoryLimit: + containerSecurityContext: + runAsUser: 65534 # nobody user + runAsGroup: 65534 # nobody group + allowPrivilegeEscalation: false + image: +- name: jupyterhub/configurable-http-proxy +- tag: 4.5.0 # https://github.com/jupyterhub/configurable-http-proxy/releases ++ name: quay.io/jupyterhub/configurable-http-proxy ++ # tag is automatically bumped to new patch versions by the ++ # watch-dependencies.yaml workflow. ++ # ++ tag: "4.6.1" # https://github.com/jupyterhub/configurable-http-proxy/tags + pullPolicy: + pullSecrets: [] + extraCommandLineFlags: [] +@@ -229,11 +241,14 @@ proxy: + enabled: true + initialDelaySeconds: 60 + periodSeconds: 10 ++ failureThreshold: 30 ++ timeoutSeconds: 3 + readinessProbe: + enabled: true + initialDelaySeconds: 0 + periodSeconds: 2 + failureThreshold: 1000 ++ timeoutSeconds: 1 + resources: {} + defaultTarget: + errorTarget: +@@ -241,12 +256,16 @@ proxy: + nodeSelector: {} + tolerations: [] + networkPolicy: +- enabled: false ++ enabled: true + ingress: [] +- egress: +- - to: +- - ipBlock: +- cidr: 0.0.0.0/0 ++ egress: [] ++ egressAllowRules: ++ cloudMetadataServer: true ++ dnsPortsCloudMetadataServer: true ++ dnsPortsKubeSystemNamespace: true ++ dnsPortsPrivateIPs: true ++ nonPrivateIPs: true ++ privateIPs: true + interNamespaceAccessLabels: ignore + allowedIngressPorts: [http, https] + pdb: +@@ -257,13 +276,17 @@ proxy: + # traefik relates to the autohttps pod, which is responsible for TLS + # termination when proxy.https.type=letsencrypt. + traefik: ++ revisionHistoryLimit: + containerSecurityContext: + runAsUser: 65534 # nobody user + runAsGroup: 65534 # nobody group + allowPrivilegeEscalation: false + image: + name: traefik +- tag: v2.4.11 # ref: https://hub.docker.com/_/traefik?tab=tags ++ # tag is automatically bumped to new patch versions by the ++ # watch-dependencies.yaml workflow. ++ # ++ tag: "v2.10.7" # ref: https://hub.docker.com/_/traefik?tab=tags + pullPolicy: + pullSecrets: [] + hsts: +@@ -272,6 +295,7 @@ proxy: + maxAge: 15724800 # About 6 months + resources: {} + labels: {} ++ extraInitContainers: [] + extraEnv: {} + extraVolumes: [] + extraVolumeMounts: [] +@@ -283,10 +307,14 @@ proxy: + networkPolicy: + enabled: true + ingress: [] +- egress: +- - to: +- - ipBlock: +- cidr: 0.0.0.0/0 ++ egress: [] ++ egressAllowRules: ++ cloudMetadataServer: true ++ dnsPortsCloudMetadataServer: true ++ dnsPortsKubeSystemNamespace: true ++ dnsPortsPrivateIPs: true ++ nonPrivateIPs: true ++ privateIPs: true + interNamespaceAccessLabels: ignore + allowedIngressPorts: [http, https] + pdb: +@@ -294,6 +322,8 @@ proxy: + maxUnavailable: + minAvailable: 1 + serviceAccount: ++ create: true ++ name: + annotations: {} + extraPodSpec: {} + secretSync: +@@ -302,8 +332,8 @@ proxy: + runAsGroup: 65534 # nobody group + allowPrivilegeEscalation: false + image: +- name: jupyterhub/k8s-secret-sync +- tag: "1.1.3" ++ name: quay.io/jupyterhub/k8s-secret-sync ++ tag: "3.2.1" + pullPolicy: + pullSecrets: [] + resources: {} +@@ -342,29 +372,27 @@ singleuser: + preferred: [] + networkTools: + image: +- name: jupyterhub/k8s-network-tools +- tag: "1.1.3" ++ name: quay.io/jupyterhub/k8s-network-tools ++ tag: "3.2.1" + pullPolicy: + pullSecrets: [] ++ resources: {} + cloudMetadata: + # block set to true will append a privileged initContainer using the + # iptables to block the sensitive metadata server at the provided ip. +- blockWithIptables: false ++ blockWithIptables: true ++ ip: 169.254.169.254 + networkPolicy: +- enabled: false ++ enabled: true + ingress: [] +- egress: +- # Required egress to communicate with the hub and DNS servers will be +- # augmented to these egress rules. +- # +- # This default rule explicitly allows all outbound traffic from singleuser +- # pods, except to a typical IP used to return metadata that can be used by +- # someone with malicious intent. +- - to: +- - ipBlock: +- cidr: 0.0.0.0/0 +- except: +- - 169.254.169.254/32 ++ egress: [] ++ egressAllowRules: ++ cloudMetadataServer: false ++ dnsPortsCloudMetadataServer: true ++ dnsPortsKubeSystemNamespace: true ++ dnsPortsPrivateIPs: true ++ nonPrivateIPs: true ++ privateIPs: false + interNamespaceAccessLabels: ignore + allowedIngressPorts: [] + events: true +@@ -376,6 +404,7 @@ singleuser: + lifecycleHooks: {} + initContainers: [] + extraContainers: [] ++ allowPrivilegeEscalation: false + uid: 1000 + fsGid: 100 + serviceAccountName: +@@ -387,29 +416,29 @@ singleuser: + static: + pvcName: + subPath: "{username}" +- capacity: 10Mi +- homeMountPath: /home/workspace ++ capacity: 10Mi # EDIT: CLOUDHARNESS ++ homeMountPath: /home/workspace # EDIT: CLOUDHARNESS + dynamic: + storageClass: +- pvcNameTemplate: jupyter-{username} +- volumeNameTemplate: jupyter-{username} ++ pvcNameTemplate: jupyter-{username} # EDIT: CLOUDHARNESS ++ volumeNameTemplate: jupyter-{username} # EDIT: CLOUDHARNESS + storageAccessModes: [ReadWriteOnce] + image: +- name: jupyter/base-notebook +- tag: "hub-1.4.2" ++ name: quay.io/jupyterhub/k8s-singleuser-sample ++ tag: "3.2.1" + pullPolicy: + pullSecrets: [] + startTimeout: 300 + cpu: +- limit: 0.4 +- guarantee: 0.05 ++ limit: 0.4 # EDIT: CLOUDHARNESS ++ guarantee: 0.05 # EDIT: CLOUDHARNESS + memory: +- limit: 0.5G +- guarantee: 0.1G ++ limit: 0.5G # EDIT: CLOUDHARNESS ++ guarantee: 0.1G # EDIT: CLOUDHARNESS + extraResource: + limits: {} + guarantees: {} +- cmd: /usr/local/bin/start-singleuser.sh ++ cmd: jupyterhub-singleuser + defaultUrl: + extraPodConfig: {} + profileList: [] +@@ -417,74 +446,146 @@ singleuser: + # scheduling relates to the user-scheduler pods and user-placeholder pods. + scheduling: + userScheduler: +- enabled: false ++ enabled: false # EDIT: CLOUDHARNESS ++ revisionHistoryLimit: + replicas: 2 + logLevel: 4 ++ # plugins are configured on the user-scheduler to make us score how we ++ # schedule user pods in a way to help us schedule on the most busy node. By ++ # doing this, we help scale down more effectively. It isn't obvious how to ++ # enable/disable scoring plugins, and configure them, to accomplish this. ++ # + # plugins ref: https://kubernetes.io/docs/reference/scheduling/config/#scheduling-plugins-1 ++ # migration ref: https://kubernetes.io/docs/reference/scheduling/config/#scheduler-configuration-migrations ++ # + plugins: + score: ++ # These scoring plugins are enabled by default according to ++ # https://kubernetes.io/docs/reference/scheduling/config/#scheduling-plugins ++ # 2022-02-22. ++ # ++ # Enabled with high priority: ++ # - NodeAffinity ++ # - InterPodAffinity ++ # - NodeResourcesFit ++ # - ImageLocality ++ # Remains enabled with low default priority: ++ # - TaintToleration ++ # - PodTopologySpread ++ # - VolumeBinding ++ # Disabled for scoring: ++ # - NodeResourcesBalancedAllocation ++ # + disabled: +- - name: SelectorSpread +- - name: TaintToleration +- - name: PodTopologySpread ++ # We disable these plugins (with regards to scoring) to not interfere ++ # or complicate our use of NodeResourcesFit. + - name: NodeResourcesBalancedAllocation +- - name: NodeResourcesLeastAllocated + # Disable plugins to be allowed to enable them again with a different + # weight and avoid an error. +- - name: NodePreferAvoidPods + - name: NodeAffinity + - name: InterPodAffinity ++ - name: NodeResourcesFit + - name: ImageLocality + enabled: +- - name: NodePreferAvoidPods +- weight: 161051 + - name: NodeAffinity + weight: 14631 + - name: InterPodAffinity + weight: 1331 +- - name: NodeResourcesMostAllocated ++ - name: NodeResourcesFit + weight: 121 + - name: ImageLocality + weight: 11 ++ pluginConfig: ++ # Here we declare that we should optimize pods to fit based on a ++ # MostAllocated strategy instead of the default LeastAllocated. ++ - name: NodeResourcesFit ++ args: ++ scoringStrategy: ++ resources: ++ - name: cpu ++ weight: 1 ++ - name: memory ++ weight: 1 ++ type: MostAllocated + containerSecurityContext: + runAsUser: 65534 # nobody user + runAsGroup: 65534 # nobody group + allowPrivilegeEscalation: false + image: + # IMPORTANT: Bumping the minor version of this binary should go hand in +- # hand with an inspection of the user-scheduelrs RBAC resources +- # that we have forked. +- name: k8s.gcr.io/kube-scheduler +- tag: v1.19.13 # ref: https://github.com/kubernetes/website/blob/main/content/en/releases/patch-releases.md ++ # hand with an inspection of the user-scheduelr's RBAC ++ # resources that we have forked in ++ # templates/scheduling/user-scheduler/rbac.yaml. ++ # ++ # Debugging advice: ++ # ++ # - Is configuration of kube-scheduler broken in ++ # templates/scheduling/user-scheduler/configmap.yaml? ++ # ++ # - Is the kube-scheduler binary's compatibility to work ++ # against a k8s api-server that is too new or too old? ++ # ++ # - You can update the GitHub workflow that runs tests to ++ # include "deploy/user-scheduler" in the k8s namespace report ++ # and reduce the user-scheduler deployments replicas to 1 in ++ # dev-config.yaml to get relevant logs from the user-scheduler ++ # pods. Inspect the "Kubernetes namespace report" action! ++ # ++ # - Typical failures are that kube-scheduler fails to search for ++ # resources via its "informers", and won't start trying to ++ # schedule pods before they succeed which may require ++ # additional RBAC permissions or that the k8s api-server is ++ # aware of the resources. ++ # ++ # - If "successfully acquired lease" can be seen in the logs, it ++ # is a good sign kube-scheduler is ready to schedule pods. ++ # ++ name: registry.k8s.io/kube-scheduler ++ # tag is automatically bumped to new patch versions by the ++ # watch-dependencies.yaml workflow. The minor version is pinned in the ++ # workflow, and should be updated there if a minor version bump is done ++ # here. We aim to stay around 1 minor version behind the latest k8s ++ # version. ++ # ++ tag: "v1.28.6" # ref: https://github.com/kubernetes/kubernetes/tree/master/CHANGELOG + pullPolicy: + pullSecrets: [] + nodeSelector: {} + tolerations: [] ++ labels: {} ++ annotations: {} + pdb: + enabled: true + maxUnavailable: 1 + minAvailable: + resources: {} + serviceAccount: ++ create: true ++ name: + annotations: {} + extraPodSpec: {} + podPriority: + enabled: false + globalDefault: false + defaultPriority: 0 ++ imagePullerPriority: -5 + userPlaceholderPriority: -10 + userPlaceholder: + enabled: true + image: +- name: k8s.gcr.io/pause +- # tag's can be updated by inspecting the output of the command: +- # gcloud container images list-tags k8s.gcr.io/pause --sort-by=~tags ++ name: registry.k8s.io/pause ++ # tag is automatically bumped to new patch versions by the ++ # watch-dependencies.yaml workflow. + # + # If you update this, also update prePuller.pause.image.tag +- tag: "3.5" ++ # ++ tag: "3.9" + pullPolicy: + pullSecrets: [] ++ revisionHistoryLimit: + replicas: 0 ++ labels: {} ++ annotations: {} + containerSecurityContext: + runAsUser: 65534 # nobody user + runAsGroup: 65534 # nobody group +@@ -517,6 +618,8 @@ scheduling: + + # prePuller relates to the hook|continuous-image-puller DaemonsSets + prePuller: ++ revisionHistoryLimit: ++ labels: {} + annotations: {} + resources: {} + containerSecurityContext: +@@ -530,8 +633,8 @@ prePuller: + pullOnlyOnChanges: true + # image and the configuration below relates to the hook-image-awaiter Job + image: +- name: jupyterhub/k8s-image-awaiter +- tag: "1.1.3" ++ name: quay.io/jupyterhub/k8s-image-awaiter ++ tag: "3.2.1" + pullPolicy: + pullSecrets: [] + containerSecurityContext: +@@ -543,6 +646,8 @@ prePuller: + tolerations: [] + resources: {} + serviceAccount: ++ create: true ++ name: + annotations: {} + continuous: + enabled: true +@@ -554,18 +659,20 @@ prePuller: + runAsGroup: 65534 # nobody group + allowPrivilegeEscalation: false + image: +- name: k8s.gcr.io/pause +- # tag's can be updated by inspecting the output of the command: +- # gcloud container images list-tags k8s.gcr.io/pause --sort-by=~tags ++ name: registry.k8s.io/pause ++ # tag is automatically bumped to new patch versions by the ++ # watch-dependencies.yaml workflow. + # + # If you update this, also update scheduling.userPlaceholder.image.tag +- tag: "3.5" ++ # ++ tag: "3.9" + pullPolicy: + pullSecrets: [] + + ingress: + enabled: false + annotations: {} ++ ingressClassName: + hosts: [] + pathSuffix: + pathType: Prefix +@@ -581,7 +688,8 @@ ingress: + cull: + enabled: true + users: false # --cull-users +- removeNamedServers: true # --remove-named-servers ++ adminUsers: true # --cull-admin-users ++ removeNamedServers: true # EDIT: CLOUDHARNESS + timeout: 3600 # --timeout + every: 600 # --cull-every + concurrency: 10 # --concurrency +diff --git a/applications/jupyterhub/zero-to-jupyterhub-k8s b/applications/jupyterhub/zero-to-jupyterhub-k8s +new file mode 160000 +index 0000000..c92c123 +--- /dev/null ++++ b/applications/jupyterhub/zero-to-jupyterhub-k8s +@@ -0,0 +1 @@ ++Subproject commit c92c12374795e84f36f5f16c4e8b8a448ad2f230-dirty diff --git a/applications/jupyterhub/update.sh b/applications/jupyterhub/update.sh new file mode 100644 index 000000000..cddf68996 --- /dev/null +++ b/applications/jupyterhub/update.sh @@ -0,0 +1,28 @@ +git clone -n git@github.com:jupyterhub/zero-to-jupyterhub-k8s.git +git checkout jupyterhub +git checkout chartpress.yaml +pip install chartpress +cd zero-to-jupyterhub-k8s +chartpress -t $1 +cd .. +cp -R zero-to-jupyterhub-k8s/jupyterhub/templates/* deploy/templates +cp zero-to-jupyterhub-k8s/jupyterhub/files/hub/* deploy/resources/hub +cp zero-to-jupyterhub-k8s/jupyterhub/values* deploy +cd deploy + +rm -Rf templates/proxy/autohttps # Proxy is not used as node balancer +rm templates/ingress.yaml # Default cloudharness ingress is used +# Command to replace everything like files/hub/ inside deploy/templates with resources/jupyterhub/hub/ +find templates -type f -exec sed -i 's/files\/hub/resources\/jupyterhub\/hub/g' {} \; + +# replace .Values.hub. with .Values.hub.config with .Values.apps.jupyterhub.hub +find templates -type f -exec sed -i 's/.Values./.Values.apps.jupyterhub./g' {} \; + +# replace .Values.apps.jupyterhub.hub.image with .Values.apps.jupyterhub.harness.deployment.image +find templates -type f -exec sed -i 's/{{ .Values.apps.jupyterhub.hub.image.name }}:{{ .Values.apps.jupyterhub.hub.image.tag }}/{{ .Values.apps.jupyterhub.harness.deployment.image }}/g' {} \; + + + +find templates -type f -exec sed -i 's$.Template.BasePath "/hub$.Template.BasePath "/jupyterhub/hub$g' {} \; +find templates -type f -exec sed -i 's$.Template.BasePath "/proxy$.Template.BasePath "/jupyterhub/proxy$g' {} \; +find templates -type f -exec sed -i 's$.Template.BasePath "/scheduling$.Template.BasePath "/jupyterhub/scheduling$g' {} \; diff --git a/deployment/codefresh-test-local.yaml b/deployment/codefresh-test-local.yaml index 612e214ba..19a91c836 100644 --- a/deployment/codefresh-test-local.yaml +++ b/deployment/codefresh-test-local.yaml @@ -32,9 +32,8 @@ steps: working_directory: . commands: - bash cloud-harness/install.sh - - harness-deployment . -n test-${{NAMESPACE_BASENAME}}-${{CF_SHORT_REVISION}} - -d ${{CF_SHORT_REVISION}}.${{DOMAIN}} -r ${{REGISTRY}} -rs ${{REGISTRY_SECRET}} - -e test-local --write-env -N -i samples + - harness-deployment . -n test-${{NAMESPACE_BASENAME}} -d ${{DOMAIN}} -r ${{REGISTRY}} + -rs ${{REGISTRY_SECRET}} -e test-local --write-env -N -i jupyterhub - cat deployment/.env >> ${{CF_VOLUME_PATH}}/env_vars_to_export - cat ${{CF_VOLUME_PATH}}/env_vars_to_export prepare_deployment_view: @@ -72,33 +71,11 @@ steps: == true forceNoCache: includes('${{CLOUDHARNESS_BASE_TAG_FORCE_BUILD}}', '{{CLOUDHARNESS_BASE_TAG_FORCE_BUILD}}') == false - cloudharness-frontend-build: - type: build - stage: build - dockerfile: infrastructure/base-images/cloudharness-frontend-build/Dockerfile - registry: '${{CODEFRESH_REGISTRY}}' - buildkit: true - build_arguments: - - DOMAIN=${{DOMAIN}} - - NOCACHE=${{CF_BUILD_ID}} - - REGISTRY=${{REGISTRY}}/cloudharness/ - image_name: cloudharness/cloudharness-frontend-build - title: Cloudharness frontend build - working_directory: ./. - tag: '${{CLOUDHARNESS_FRONTEND_BUILD_TAG}}' - when: - condition: - any: - buildDoesNotExist: includes('${{CLOUDHARNESS_FRONTEND_BUILD_TAG_EXISTS}}', - '{{CLOUDHARNESS_FRONTEND_BUILD_TAG_EXISTS}}') == true - forceNoCache: includes('${{CLOUDHARNESS_FRONTEND_BUILD_TAG_FORCE_BUILD}}', - '{{CLOUDHARNESS_FRONTEND_BUILD_TAG_FORCE_BUILD}}') == false - build_static_images: - title: Build static images + build_application_images: type: parallel stage: build steps: - cloudharness-flask: + accounts: type: build stage: build dockerfile: Dockerfile @@ -108,23 +85,18 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_BASE=${{REGISTRY}}/cloudharness/cloudharness-base:${{CLOUDHARNESS_BASE_TAG}} - image_name: cloudharness/cloudharness-flask - title: Cloudharness flask - working_directory: ./infrastructure/common-images/cloudharness-flask - tag: '${{CLOUDHARNESS_FLASK_TAG}}' + image_name: cloudharness/accounts + title: Accounts + working_directory: ./applications/accounts + tag: '${{ACCOUNTS_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{CLOUDHARNESS_FLASK_TAG_EXISTS}}', '{{CLOUDHARNESS_FLASK_TAG_EXISTS}}') + buildDoesNotExist: includes('${{ACCOUNTS_TAG_EXISTS}}', '{{ACCOUNTS_TAG_EXISTS}}') == true - forceNoCache: includes('${{CLOUDHARNESS_FLASK_TAG_FORCE_BUILD}}', '{{CLOUDHARNESS_FLASK_TAG_FORCE_BUILD}}') + forceNoCache: includes('${{ACCOUNTS_TAG_FORCE_BUILD}}', '{{ACCOUNTS_TAG_FORCE_BUILD}}') == false - build_application_images: - type: parallel - stage: build - steps: - nfsserver: + jupyterhub: type: build stage: build dockerfile: Dockerfile @@ -134,18 +106,19 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - image_name: cloudharness/nfsserver - title: Nfsserver - working_directory: ./applications/nfsserver - tag: '${{NFSSERVER_TAG}}' + - CLOUDHARNESS_BASE=${{REGISTRY}}/cloudharness/cloudharness-base:${{CLOUDHARNESS_BASE_TAG}} + image_name: cloudharness/jupyterhub + title: Jupyterhub + working_directory: ./applications/jupyterhub + tag: '${{JUPYTERHUB_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{NFSSERVER_TAG_EXISTS}}', '{{NFSSERVER_TAG_EXISTS}}') + buildDoesNotExist: includes('${{JUPYTERHUB_TAG_EXISTS}}', '{{JUPYTERHUB_TAG_EXISTS}}') == true - forceNoCache: includes('${{NFSSERVER_TAG_FORCE_BUILD}}', '{{NFSSERVER_TAG_FORCE_BUILD}}') + forceNoCache: includes('${{JUPYTERHUB_TAG_FORCE_BUILD}}', '{{JUPYTERHUB_TAG_FORCE_BUILD}}') == false - accounts: + jupyterhub-zero-to-jupyterhub-k8s-images-secret-sync: type: build stage: build dockerfile: Dockerfile @@ -155,18 +128,20 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - image_name: cloudharness/accounts - title: Accounts - working_directory: ./applications/accounts - tag: '${{ACCOUNTS_TAG}}' + image_name: cloudharness/jupyterhub-zero-to-jupyterhub-k8s-images-secret-sync + title: Jupyterhub zero to jupyterhub k8s images secret sync + working_directory: ./applications/jupyterhub/zero-to-jupyterhub-k8s/images/secret-sync + tag: '${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SECRET_SYNC_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{ACCOUNTS_TAG_EXISTS}}', '{{ACCOUNTS_TAG_EXISTS}}') + buildDoesNotExist: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SECRET_SYNC_TAG_EXISTS}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SECRET_SYNC_TAG_EXISTS}}') == true - forceNoCache: includes('${{ACCOUNTS_TAG_FORCE_BUILD}}', '{{ACCOUNTS_TAG_FORCE_BUILD}}') + forceNoCache: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SECRET_SYNC_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SECRET_SYNC_TAG_FORCE_BUILD}}') == false - samples: + jupyterhub-zero-to-jupyterhub-k8s-images-image-awaiter: type: build stage: build dockerfile: Dockerfile @@ -176,20 +151,20 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_FRONTEND_BUILD=${{REGISTRY}}/cloudharness/cloudharness-frontend-build:${{CLOUDHARNESS_FRONTEND_BUILD_TAG}} - - CLOUDHARNESS_FLASK=${{REGISTRY}}/cloudharness/cloudharness-flask:${{CLOUDHARNESS_FLASK_TAG}} - image_name: cloudharness/samples - title: Samples - working_directory: ./applications/samples - tag: '${{SAMPLES_TAG}}' + image_name: cloudharness/jupyterhub-zero-to-jupyterhub-k8s-images-image-awaiter + title: Jupyterhub zero to jupyterhub k8s images image awaiter + working_directory: ./applications/jupyterhub/zero-to-jupyterhub-k8s/images/image-awaiter + tag: '${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_IMAGE_AWAITER_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{SAMPLES_TAG_EXISTS}}', '{{SAMPLES_TAG_EXISTS}}') + buildDoesNotExist: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_IMAGE_AWAITER_TAG_EXISTS}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_IMAGE_AWAITER_TAG_EXISTS}}') == true - forceNoCache: includes('${{SAMPLES_TAG_FORCE_BUILD}}', '{{SAMPLES_TAG_FORCE_BUILD}}') + forceNoCache: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_IMAGE_AWAITER_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_IMAGE_AWAITER_TAG_FORCE_BUILD}}') == false - samples-print-file: + jupyterhub-zero-to-jupyterhub-k8s-images-singleuser-sample: type: build stage: build dockerfile: Dockerfile @@ -199,19 +174,20 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_BASE=${{REGISTRY}}/cloudharness/cloudharness-base:${{CLOUDHARNESS_BASE_TAG}} - image_name: cloudharness/samples-print-file - title: Samples print file - working_directory: ./applications/samples/tasks/print-file - tag: '${{SAMPLES_PRINT_FILE_TAG}}' + image_name: cloudharness/jupyterhub-zero-to-jupyterhub-k8s-images-singleuser-sample + title: Jupyterhub zero to jupyterhub k8s images singleuser sample + working_directory: ./applications/jupyterhub/zero-to-jupyterhub-k8s/images/singleuser-sample + tag: '${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SINGLEUSER_SAMPLE_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{SAMPLES_PRINT_FILE_TAG_EXISTS}}', '{{SAMPLES_PRINT_FILE_TAG_EXISTS}}') + buildDoesNotExist: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SINGLEUSER_SAMPLE_TAG_EXISTS}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SINGLEUSER_SAMPLE_TAG_EXISTS}}') == true - forceNoCache: includes('${{SAMPLES_PRINT_FILE_TAG_FORCE_BUILD}}', '{{SAMPLES_PRINT_FILE_TAG_FORCE_BUILD}}') + forceNoCache: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SINGLEUSER_SAMPLE_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_SINGLEUSER_SAMPLE_TAG_FORCE_BUILD}}') == false - samples-secret: + jupyterhub-zero-to-jupyterhub-k8s-images-network-tools: type: build stage: build dockerfile: Dockerfile @@ -221,19 +197,20 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_BASE=${{REGISTRY}}/cloudharness/cloudharness-base:${{CLOUDHARNESS_BASE_TAG}} - image_name: cloudharness/samples-secret - title: Samples secret - working_directory: ./applications/samples/tasks/secret - tag: '${{SAMPLES_SECRET_TAG}}' + image_name: cloudharness/jupyterhub-zero-to-jupyterhub-k8s-images-network-tools + title: Jupyterhub zero to jupyterhub k8s images network tools + working_directory: ./applications/jupyterhub/zero-to-jupyterhub-k8s/images/network-tools + tag: '${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_NETWORK_TOOLS_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{SAMPLES_SECRET_TAG_EXISTS}}', '{{SAMPLES_SECRET_TAG_EXISTS}}') + buildDoesNotExist: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_NETWORK_TOOLS_TAG_EXISTS}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_NETWORK_TOOLS_TAG_EXISTS}}') == true - forceNoCache: includes('${{SAMPLES_SECRET_TAG_FORCE_BUILD}}', '{{SAMPLES_SECRET_TAG_FORCE_BUILD}}') + forceNoCache: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_NETWORK_TOOLS_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_NETWORK_TOOLS_TAG_FORCE_BUILD}}') == false - samples-sum: + jupyterhub-zero-to-jupyterhub-k8s-images-hub: type: build stage: build dockerfile: Dockerfile @@ -243,19 +220,20 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_BASE=${{REGISTRY}}/cloudharness/cloudharness-base:${{CLOUDHARNESS_BASE_TAG}} - image_name: cloudharness/samples-sum - title: Samples sum - working_directory: ./applications/samples/tasks/sum - tag: '${{SAMPLES_SUM_TAG}}' + image_name: cloudharness/jupyterhub-zero-to-jupyterhub-k8s-images-hub + title: Jupyterhub zero to jupyterhub k8s images hub + working_directory: ./applications/jupyterhub/zero-to-jupyterhub-k8s/images/hub + tag: '${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_HUB_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{SAMPLES_SUM_TAG_EXISTS}}', '{{SAMPLES_SUM_TAG_EXISTS}}') - == true - forceNoCache: includes('${{SAMPLES_SUM_TAG_FORCE_BUILD}}', '{{SAMPLES_SUM_TAG_FORCE_BUILD}}') + buildDoesNotExist: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_HUB_TAG_EXISTS}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_HUB_TAG_EXISTS}}') == + true + forceNoCache: includes('${{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_HUB_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_ZERO_TO_JUPYTERHUB_K8S_IMAGES_HUB_TAG_FORCE_BUILD}}') == false - common: + jupyterhub-jupyterhub: type: build stage: build dockerfile: Dockerfile @@ -265,19 +243,18 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_FLASK=${{REGISTRY}}/cloudharness/cloudharness-flask:${{CLOUDHARNESS_FLASK_TAG}} - image_name: cloudharness/common - title: Common - working_directory: ./applications/common/server - tag: '${{COMMON_TAG}}' + image_name: cloudharness/jupyterhub-jupyterhub + title: Jupyterhub jupyterhub + working_directory: ./applications/jupyterhub/src/jupyterhub + tag: '${{JUPYTERHUB_JUPYTERHUB_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{COMMON_TAG_EXISTS}}', '{{COMMON_TAG_EXISTS}}') - == true - forceNoCache: includes('${{COMMON_TAG_FORCE_BUILD}}', '{{COMMON_TAG_FORCE_BUILD}}') - == false - workflows-send-result-event: + buildDoesNotExist: includes('${{JUPYTERHUB_JUPYTERHUB_TAG_EXISTS}}', + '{{JUPYTERHUB_JUPYTERHUB_TAG_EXISTS}}') == true + forceNoCache: includes('${{JUPYTERHUB_JUPYTERHUB_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_JUPYTERHUB_TAG_FORCE_BUILD}}') == false + jupyterhub-jupyterhub-singleuser: type: build stage: build dockerfile: Dockerfile @@ -287,19 +264,18 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_BASE=${{REGISTRY}}/cloudharness/cloudharness-base:${{CLOUDHARNESS_BASE_TAG}} - image_name: cloudharness/workflows-send-result-event - title: Workflows send result event - working_directory: ./applications/workflows/tasks/send-result-event - tag: '${{WORKFLOWS_SEND_RESULT_EVENT_TAG}}' + image_name: cloudharness/jupyterhub-jupyterhub-singleuser + title: Jupyterhub jupyterhub singleuser + working_directory: ./applications/jupyterhub/src/jupyterhub/singleuser + tag: '${{JUPYTERHUB_JUPYTERHUB_SINGLEUSER_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{WORKFLOWS_SEND_RESULT_EVENT_TAG_EXISTS}}', - '{{WORKFLOWS_SEND_RESULT_EVENT_TAG_EXISTS}}') == true - forceNoCache: includes('${{WORKFLOWS_SEND_RESULT_EVENT_TAG_FORCE_BUILD}}', - '{{WORKFLOWS_SEND_RESULT_EVENT_TAG_FORCE_BUILD}}') == false - workflows-extract-download: + buildDoesNotExist: includes('${{JUPYTERHUB_JUPYTERHUB_SINGLEUSER_TAG_EXISTS}}', + '{{JUPYTERHUB_JUPYTERHUB_SINGLEUSER_TAG_EXISTS}}') == true + forceNoCache: includes('${{JUPYTERHUB_JUPYTERHUB_SINGLEUSER_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_JUPYTERHUB_SINGLEUSER_TAG_FORCE_BUILD}}') == false + jupyterhub-jupyterhub-examples-service-fastapi: type: build stage: build dockerfile: Dockerfile @@ -309,18 +285,20 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - image_name: cloudharness/workflows-extract-download - title: Workflows extract download - working_directory: ./applications/workflows/tasks/extract-download - tag: '${{WORKFLOWS_EXTRACT_DOWNLOAD_TAG}}' + image_name: cloudharness/jupyterhub-jupyterhub-examples-service-fastapi + title: Jupyterhub jupyterhub examples service fastapi + working_directory: ./applications/jupyterhub/src/jupyterhub/examples/service-fastapi + tag: '${{JUPYTERHUB_JUPYTERHUB_EXAMPLES_SERVICE_FASTAPI_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{WORKFLOWS_EXTRACT_DOWNLOAD_TAG_EXISTS}}', - '{{WORKFLOWS_EXTRACT_DOWNLOAD_TAG_EXISTS}}') == true - forceNoCache: includes('${{WORKFLOWS_EXTRACT_DOWNLOAD_TAG_FORCE_BUILD}}', - '{{WORKFLOWS_EXTRACT_DOWNLOAD_TAG_FORCE_BUILD}}') == false - workflows-notify-queue: + buildDoesNotExist: includes('${{JUPYTERHUB_JUPYTERHUB_EXAMPLES_SERVICE_FASTAPI_TAG_EXISTS}}', + '{{JUPYTERHUB_JUPYTERHUB_EXAMPLES_SERVICE_FASTAPI_TAG_EXISTS}}') == + true + forceNoCache: includes('${{JUPYTERHUB_JUPYTERHUB_EXAMPLES_SERVICE_FASTAPI_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_JUPYTERHUB_EXAMPLES_SERVICE_FASTAPI_TAG_FORCE_BUILD}}') + == false + jupyterhub-jupyterhub-examples-postgres-db: type: build stage: build dockerfile: Dockerfile @@ -330,19 +308,19 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_BASE=${{REGISTRY}}/cloudharness/cloudharness-base:${{CLOUDHARNESS_BASE_TAG}} - image_name: cloudharness/workflows-notify-queue - title: Workflows notify queue - working_directory: ./applications/workflows/tasks/notify-queue - tag: '${{WORKFLOWS_NOTIFY_QUEUE_TAG}}' + image_name: cloudharness/jupyterhub-jupyterhub-examples-postgres-db + title: Jupyterhub jupyterhub examples postgres db + working_directory: ./applications/jupyterhub/src/jupyterhub/examples/postgres/db + tag: '${{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_DB_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{WORKFLOWS_NOTIFY_QUEUE_TAG_EXISTS}}', - '{{WORKFLOWS_NOTIFY_QUEUE_TAG_EXISTS}}') == true - forceNoCache: includes('${{WORKFLOWS_NOTIFY_QUEUE_TAG_FORCE_BUILD}}', - '{{WORKFLOWS_NOTIFY_QUEUE_TAG_FORCE_BUILD}}') == false - workflows: + buildDoesNotExist: includes('${{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_DB_TAG_EXISTS}}', + '{{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_DB_TAG_EXISTS}}') == true + forceNoCache: includes('${{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_DB_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_DB_TAG_FORCE_BUILD}}') + == false + jupyterhub-jupyterhub-examples-postgres-hub: type: build stage: build dockerfile: Dockerfile @@ -352,50 +330,19 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_FLASK=${{REGISTRY}}/cloudharness/cloudharness-flask:${{CLOUDHARNESS_FLASK_TAG}} - image_name: cloudharness/workflows - title: Workflows - working_directory: ./applications/workflows/server - tag: '${{WORKFLOWS_TAG}}' + image_name: cloudharness/jupyterhub-jupyterhub-examples-postgres-hub + title: Jupyterhub jupyterhub examples postgres hub + working_directory: ./applications/jupyterhub/src/jupyterhub/examples/postgres/hub + tag: '${{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_HUB_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{WORKFLOWS_TAG_EXISTS}}', '{{WORKFLOWS_TAG_EXISTS}}') - == true - forceNoCache: includes('${{WORKFLOWS_TAG_FORCE_BUILD}}', '{{WORKFLOWS_TAG_FORCE_BUILD}}') + buildDoesNotExist: includes('${{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_HUB_TAG_EXISTS}}', + '{{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_HUB_TAG_EXISTS}}') == true + forceNoCache: includes('${{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_HUB_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_JUPYTERHUB_EXAMPLES_POSTGRES_HUB_TAG_FORCE_BUILD}}') == false - tests_unit: - stage: unittest - type: parallel - steps: - samples_ut: - title: Unit tests for samples - commands: - - pytest /usr/src/app/samples/test - image: '${{REGISTRY}}/cloudharness/samples:${{SAMPLES_TAG}}' - deployment: - stage: deploy - type: helm - working_directory: ./${{CF_REPO_NAME}} - title: Installing chart - arguments: - helm_version: 3.6.2 - chart_name: deployment/helm - release_name: test-${{NAMESPACE_BASENAME}}-${{CF_SHORT_REVISION}} - kube_context: '${{CLUSTER_NAME}}' - namespace: test-${{NAMESPACE_BASENAME}}-${{CF_SHORT_REVISION}} - chart_version: '${{CF_BUILD_ID}}' - cmd_ps: --timeout 600s --create-namespace - custom_value_files: - - ./deployment/helm/values.yaml - custom_values: - - apps_samples_harness_secrets_asecret=${{ASECRET}} - build_test_images: - title: Build test images - type: parallel - stage: qa - steps: - test-e2e: + jupyterhub-jupyterhub-demo-image: type: build stage: build dockerfile: Dockerfile @@ -405,128 +352,58 @@ steps: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - image_name: cloudharness/test-e2e - title: Test e2e - working_directory: ./test/test-e2e - tag: '${{TEST_E2E_TAG}}' + image_name: cloudharness/jupyterhub-jupyterhub-demo-image + title: Jupyterhub jupyterhub demo image + working_directory: ./applications/jupyterhub/src/jupyterhub/demo-image + tag: '${{JUPYTERHUB_JUPYTERHUB_DEMO_IMAGE_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{TEST_E2E_TAG_EXISTS}}', '{{TEST_E2E_TAG_EXISTS}}') - == true - forceNoCache: includes('${{TEST_E2E_TAG_FORCE_BUILD}}', '{{TEST_E2E_TAG_FORCE_BUILD}}') - == false - test-api: + buildDoesNotExist: includes('${{JUPYTERHUB_JUPYTERHUB_DEMO_IMAGE_TAG_EXISTS}}', + '{{JUPYTERHUB_JUPYTERHUB_DEMO_IMAGE_TAG_EXISTS}}') == true + forceNoCache: includes('${{JUPYTERHUB_JUPYTERHUB_DEMO_IMAGE_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_JUPYTERHUB_DEMO_IMAGE_TAG_FORCE_BUILD}}') == false + jupyterhub-jupyterhub-onbuild: type: build stage: build - dockerfile: test/test-api/Dockerfile + dockerfile: Dockerfile registry: '${{CODEFRESH_REGISTRY}}' buildkit: true build_arguments: - DOMAIN=${{DOMAIN}} - NOCACHE=${{CF_BUILD_ID}} - REGISTRY=${{REGISTRY}}/cloudharness/ - - CLOUDHARNESS_BASE=${{REGISTRY}}/cloudharness/cloudharness-base:${{CLOUDHARNESS_BASE_TAG}} - image_name: cloudharness/test-api - title: Test api - working_directory: ./. - tag: '${{TEST_API_TAG}}' + image_name: cloudharness/jupyterhub-jupyterhub-onbuild + title: Jupyterhub jupyterhub onbuild + working_directory: ./applications/jupyterhub/src/jupyterhub/onbuild + tag: '${{JUPYTERHUB_JUPYTERHUB_ONBUILD_TAG}}' when: condition: any: - buildDoesNotExist: includes('${{TEST_API_TAG_EXISTS}}', '{{TEST_API_TAG_EXISTS}}') - == true - forceNoCache: includes('${{TEST_API_TAG_FORCE_BUILD}}', '{{TEST_API_TAG_FORCE_BUILD}}') - == false - wait_deployment: - stage: qa - title: Wait deployment to be ready - image: codefresh/kubectl - commands: - - kubectl config use-context ${{CLUSTER_NAME}} - - kubectl config set-context --current --namespace=test-${{NAMESPACE_BASENAME}}-${{CF_SHORT_REVISION}} - - kubectl rollout status deployment/accounts - - kubectl rollout status deployment/samples - - kubectl rollout status deployment/common - - kubectl rollout status deployment/workflows - - sleep 60 - tests_api: - stage: qa - title: Api tests - working_directory: /home/test - image: '${{REGISTRY}}/cloudharness/test-api:${{TEST_API_TAG}}' - fail_fast: false - commands: - - echo $APP_NAME - scale: - samples_api_test: - title: samples api test - volumes: - - '${{CF_REPO_NAME}}/applications/samples:/home/test' - - '${{CF_REPO_NAME}}/deployment/helm/values.yaml:/opt/cloudharness/resources/allvalues.yaml' - environment: - - APP_URL=https://samples.${{CF_SHORT_REVISION}}.${{DOMAIN}}/api - - USERNAME=sample@testuser.com - - PASSWORD=test - commands: - - st --pre-run cloudharness_test.apitest_init run api/openapi.yaml --base-url - https://samples.${{CF_SHORT_REVISION}}.${{DOMAIN}}/api -c all --skip-deprecated-operations - --hypothesis-suppress-health-check=too_slow --hypothesis-deadline=180000 - --request-timeout=180000 --hypothesis-max-examples=2 --show-errors-tracebacks - - pytest -v test/api - common_api_test: - title: common api test - volumes: - - '${{CF_REPO_NAME}}/applications/common:/home/test' - - '${{CF_REPO_NAME}}/deployment/helm/values.yaml:/opt/cloudharness/resources/allvalues.yaml' - environment: - - APP_URL=https://common.${{CF_SHORT_REVISION}}.${{DOMAIN}}/api - commands: - - st --pre-run cloudharness_test.apitest_init run api/openapi.yaml --base-url - https://common.${{CF_SHORT_REVISION}}.${{DOMAIN}}/api -c all - workflows_api_test: - title: workflows api test - volumes: - - '${{CF_REPO_NAME}}/applications/workflows:/home/test' - - '${{CF_REPO_NAME}}/deployment/helm/values.yaml:/opt/cloudharness/resources/allvalues.yaml' - environment: - - APP_URL=https://workflows.${{CF_SHORT_REVISION}}.${{DOMAIN}}/api - commands: - - st --pre-run cloudharness_test.apitest_init run api/openapi.yaml --base-url - https://workflows.${{CF_SHORT_REVISION}}.${{DOMAIN}}/api -c all - hooks: - on_fail: - exec: - image: alpine - commands: - - cf_export FAILED=failed - tests_e2e: - stage: qa - title: End to end tests - working_directory: /home/test - image: '${{REGISTRY}}/cloudharness/test-e2e:${{TEST_E2E_TAG}}' - fail_fast: false - commands: - - yarn test - scale: - samples_e2e_test: - title: samples e2e test - volumes: - - '${{CF_REPO_NAME}}/applications/samples/test/e2e:/home/test/__tests__/samples' - environment: - - APP_URL=https://samples.${{CF_SHORT_REVISION}}.${{DOMAIN}} - - USERNAME=sample@testuser.com - - PASSWORD=test - hooks: - on_fail: - exec: - image: alpine - commands: - - cf_export FAILED=failed + buildDoesNotExist: includes('${{JUPYTERHUB_JUPYTERHUB_ONBUILD_TAG_EXISTS}}', + '{{JUPYTERHUB_JUPYTERHUB_ONBUILD_TAG_EXISTS}}') == true + forceNoCache: includes('${{JUPYTERHUB_JUPYTERHUB_ONBUILD_TAG_FORCE_BUILD}}', + '{{JUPYTERHUB_JUPYTERHUB_ONBUILD_TAG_FORCE_BUILD}}') == false + deployment: + stage: deploy + type: helm + working_directory: ./${{CF_REPO_NAME}} + title: Installing chart + arguments: + helm_version: 3.6.2 + chart_name: deployment/helm + release_name: test-${{NAMESPACE_BASENAME}} + kube_context: '${{CLUSTER_NAME}}' + namespace: test-${{NAMESPACE_BASENAME}} + chart_version: '${{CF_SHORT_REVISION}}' + cmd_ps: --timeout 600s --create-namespace + custom_value_files: + - ./deployment/helm/values.yaml + custom_values: [] approval: type: pending-approval stage: qa - title: Approve with failed tests + title: Approve anyway and delete deployment description: The pipeline will fail after ${{WAIT_ON_FAIL}} minutes timeout: timeUnit: minutes @@ -536,21 +413,11 @@ steps: condition: all: error: '"${{FAILED}}" == "failed"' - wait_on_fail: '${{WAIT_ON_FAIL}}' - dummy_end: - title: Dummy step - description: Without this, the on_finish hook is executed before the approval - step - image: python:3.9.10 - stage: qa - when: - condition: - all: - error: '"${{FAILED}}" == "failed"' - wait_on_fail: '${{WAIT_ON_FAIL}}' -hooks: - on_finish: + delete_deployment: + title: Delete deployment + description: The deployment is deleted at the end of the pipeline image: codefresh/kubectl + stage: qa commands: - kubectl config use-context ${{CLUSTER_NAME}} - - kubectl delete ns test-${{NAMESPACE_BASENAME}}-${{CF_SHORT_REVISION}} + - kubectl delete ns test-${{NAMESPACE_BASENAME}} From f87869b8462be4bebe18b3eb9adf2c63392eaf1f Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Mon, 22 Jan 2024 12:38:05 +0100 Subject: [PATCH 04/37] CH-110 jupyterhub update OK; add tests --- .../deploy/resources/hub/jupyterhub_config.py | 6 ++-- .../jupyterhub/deploy/values-test.yaml | 7 +++++ applications/jupyterhub/deploy/values.yaml | 6 ++++ .../harness_jupyter/jupyterhub.py | 2 +- applications/samples/deploy/values-test.yaml | 8 +++++ deployment/codefresh-test.yaml | 30 +++++++++++++++++++ 6 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 applications/jupyterhub/deploy/values-test.yaml diff --git a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py index 5ebe20b5d..8fdfa8c18 100755 --- a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py +++ b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py @@ -12,8 +12,6 @@ #CLOUDHARNESS: EDIT START import logging -from kubernetes import client -from jupyterhub.utils import url_path_join try: from harness_jupyter.jupyterhub import harness_hub @@ -492,6 +490,7 @@ def camelCaseify(s): cfg.pop("keys", None) c[app].update(cfg) + # load /usr/local/etc/jupyterhub/jupyterhub_config.d config files config_dir = "/usr/local/etc/jupyterhub/jupyterhub_config.d" if os.path.isdir(config_dir): @@ -560,4 +559,5 @@ def camelCaseify(s): c.registry = get_config('registry') c.domain = get_config('root.domain') c.namespace = get_config('root.namespace') -# CLOUDHARNESS: EDIT END \ No newline at end of file +# CLOUDHARNESS: EDIT END + \ No newline at end of file diff --git a/applications/jupyterhub/deploy/values-test.yaml b/applications/jupyterhub/deploy/values-test.yaml new file mode 100644 index 000000000..3ca312d39 --- /dev/null +++ b/applications/jupyterhub/deploy/values-test.yaml @@ -0,0 +1,7 @@ +harness: + accounts: + users: + - username: samplehub@testuser.com + realmRoles: + - offline_access + diff --git a/applications/jupyterhub/deploy/values.yaml b/applications/jupyterhub/deploy/values.yaml index 41e108d69..b871b33b4 100755 --- a/applications/jupyterhub/deploy/values.yaml +++ b/applications/jupyterhub/deploy/values.yaml @@ -25,6 +25,12 @@ harness: # EDIT: CLOUDHARNESS quota-ws-maxmem: 0.5 # sets the storage dedicated to the user data in Gb units (float) quota-storage-max: 1.25 + test: + e2e: + enabled: true + smoketest: true + ignoreRequestErrors: false + ignoreConsoleErrors: false # fullnameOverride and nameOverride distinguishes blank strings, null values, # and non-blank strings. For more details, see the configuration reference. diff --git a/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py b/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py index 220883a8d..fc4d0dd02 100644 --- a/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py +++ b/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py @@ -139,7 +139,7 @@ def change_pod_manifest(self: KubeSpawner): if 'subdomain' in harness and harness['subdomain'] == subdomain: ws_image = getattr(self, "ws_image", None) - logging.info("Subdomain is", subdomain) + logging.info("Subdomain is %s", subdomain) if ws_image: # try getting the image + tag from values.yaml ch_conf = conf.get_configuration() diff --git a/applications/samples/deploy/values-test.yaml b/applications/samples/deploy/values-test.yaml index 3555108f9..14274fd60 100644 --- a/applications/samples/deploy/values-test.yaml +++ b/applications/samples/deploy/values-test.yaml @@ -1,4 +1,12 @@ harness: + dependencies: + soft: + - workflows + - events + - accounts + - common + - nfsserver + - jupyterhub accounts: roles: - role1 diff --git a/deployment/codefresh-test.yaml b/deployment/codefresh-test.yaml index ff7a88aff..7280c8e6c 100644 --- a/deployment/codefresh-test.yaml +++ b/deployment/codefresh-test.yaml @@ -165,6 +165,28 @@ steps: == true forceNoCache: includes('${{ACCOUNTS_TAG_FORCE_BUILD}}', '{{ACCOUNTS_TAG_FORCE_BUILD}}') == false + jupyterhub: + type: build + stage: build + dockerfile: Dockerfile + registry: '${{CODEFRESH_REGISTRY}}' + buildkit: true + build_arguments: + - DOMAIN=${{DOMAIN}} + - NOCACHE=${{CF_BUILD_ID}} + - REGISTRY=${{REGISTRY}}/cloudharness/ + - CLOUDHARNESS_BASE=${{REGISTRY}}/cloudharness/cloudharness-base:${{CLOUDHARNESS_BASE_TAG}} + image_name: cloudharness/jupyterhub + title: Jupyterhub + working_directory: ./applications/jupyterhub + tag: '${{JUPYTERHUB_TAG}}' + when: + condition: + any: + buildDoesNotExist: includes('${{JUPYTERHUB_TAG_EXISTS}}', '{{JUPYTERHUB_TAG_EXISTS}}') + == true + forceNoCache: includes('${{JUPYTERHUB_TAG_FORCE_BUILD}}', '{{JUPYTERHUB_TAG_FORCE_BUILD}}') + == false samples: type: build stage: build @@ -510,6 +532,14 @@ steps: commands: - yarn test scale: + jupyterhub_e2e_test: + title: jupyterhub e2e test + volumes: + - '${{CF_REPO_NAME}}/applications/jupyterhub/test/e2e:/home/test/__tests__/jupyterhub' + environment: + - APP_URL=https://hub.${{DOMAIN}} + - USERNAME=samplehub@testuser.com + - PASSWORD=test samples_e2e_test: title: samples e2e test volumes: From 9c905eb17cc78d39c5fc560bc5f250ab649ec7ba Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Mon, 22 Jan 2024 15:13:19 +0100 Subject: [PATCH 05/37] CH-110 fix test --- applications/jupyterhub/deploy/values-test.yaml | 6 ------ deployment/codefresh-test.yaml | 4 +++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/applications/jupyterhub/deploy/values-test.yaml b/applications/jupyterhub/deploy/values-test.yaml index 3ca312d39..8b1378917 100644 --- a/applications/jupyterhub/deploy/values-test.yaml +++ b/applications/jupyterhub/deploy/values-test.yaml @@ -1,7 +1 @@ -harness: - accounts: - users: - - username: samplehub@testuser.com - realmRoles: - - offline_access diff --git a/deployment/codefresh-test.yaml b/deployment/codefresh-test.yaml index bbedd788f..d15db5cd1 100644 --- a/deployment/codefresh-test.yaml +++ b/deployment/codefresh-test.yaml @@ -467,7 +467,9 @@ steps: - kubectl config use-context ${{CLUSTER_NAME}} - kubectl config set-context --current --namespace=test-${{NAMESPACE_BASENAME}} - kubectl rollout status deployment/accounts + - kubectl rollout status deployment/argo-server-gk - kubectl rollout status deployment/samples + - kubectl rollout status deployment/samples-gk - kubectl rollout status deployment/common - kubectl rollout status deployment/workflows - sleep 60 @@ -536,7 +538,7 @@ steps: - '${{CF_REPO_NAME}}/applications/jupyterhub/test/e2e:/home/test/__tests__/jupyterhub' environment: - APP_URL=https://hub.${{DOMAIN}} - - USERNAME=samplehub@testuser.com + - USERNAME=sample@testuser.com - PASSWORD=test samples_e2e_test: title: samples e2e test From 313b9e47491c5c2c1a8795dab01147893245dc8d Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Mon, 22 Jan 2024 16:52:10 +0100 Subject: [PATCH 06/37] CH-110 Disable hub network policy --- applications/jupyterhub/deploy/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/jupyterhub/deploy/values.yaml b/applications/jupyterhub/deploy/values.yaml index b871b33b4..9be3ad5dd 100755 --- a/applications/jupyterhub/deploy/values.yaml +++ b/applications/jupyterhub/deploy/values.yaml @@ -136,7 +136,7 @@ hub: maxUnavailable: minAvailable: 1 networkPolicy: - enabled: true + enabled: false # EDIT: CLOUDHARNESS -- cannot connect to accounts otherwise ingress: [] egress: [] egressAllowRules: From 24132a5d52e806d21cfabad02345f6140ecfebf6 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 23 Jan 2024 16:38:26 +0100 Subject: [PATCH 07/37] CH-94 add control on image prepull --- .../image-puller/_helpers-daemonset.tpl | 20 ++++++++++++ .../jupyterhub/deploy/values-test.yaml | 6 +++- docs/jupyterhub.md | 31 ++++++++++++++++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl b/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl index 528345c08..f872a3367 100644 --- a/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl +++ b/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl @@ -199,7 +199,27 @@ spec: securityContext: {{- . | toYaml | nindent 12 }} {{- end }} + {{- end }} + {{- /* --- EDIT: CLOUDHARNESS pull images --- */}} + {{- if $.Values.apps.jupyterhub.harness.jupyterhub.prepull -}} + {{- range $k, $v := $.Values.apps.jupyterhub.harness.jupyterhub.prepull }} + - name: image-pull--{{ $v }} + image: {{ get ( get $.Values "task-images" ) $v }} + command: + - /bin/sh + - -c + - echo "Pulling complete" + {{- with $.Values.apps.jupyterhub.prePuller.resources }} + resources: + {{- . | toYaml | nindent 12 }} + {{- end }} + {{- with $.Values.apps.jupyterhub.prePuller.containerSecurityContext }} + securityContext: + {{- . | toYaml | nindent 12 }} + {{- end }} {{- end }} + {{- end }} + {{- /* --- END EDIT: CLOUDHARNESS pull images --- */}} containers: - name: pause image: {{ .Values.apps.jupyterhub.prePuller.pause.image.name }}:{{ .Values.apps.jupyterhub.prePuller.pause.image.tag }} diff --git a/applications/jupyterhub/deploy/values-test.yaml b/applications/jupyterhub/deploy/values-test.yaml index 8b1378917..653cae1e3 100644 --- a/applications/jupyterhub/deploy/values-test.yaml +++ b/applications/jupyterhub/deploy/values-test.yaml @@ -1 +1,5 @@ - +harness: + jupyterhub: + prepull: + - cloudharness-base + diff --git a/docs/jupyterhub.md b/docs/jupyterhub.md index 709ede5f1..3d7046bca 100644 --- a/docs/jupyterhub.md +++ b/docs/jupyterhub.md @@ -35,6 +35,7 @@ Edit the `deploy/values.yaml` file `harness.jupyterhub` section to edit configu - `applicationHook`: change the hook function (advances, see below) - `extraConfig`: allows you to add Python snippets to the jupyterhub_config.py file - `spawnerExtraConfig`: allows you to add values to the spawner object without the need of creating a new hook +- `prepull`: indicate images that will be prepulled from the current build Example: ```yaml @@ -46,6 +47,8 @@ harness: name: proxy-public jupyterhub: args: ["--debug", "--NotebookApp.default_url=/lab"] + prepull: + - cloudharness-base extraConfig: timing: | c.Spawner.port = 8000 @@ -179,4 +182,30 @@ Cloudharness JupyterHub is integrated with the accounts service so enabling a sh The spawner is also adapted providing a hook to allow other applications to be based on the hub spawner to run with their own configurations. -Available \ No newline at end of file +Available + +## Prepull configuration +Image prepull can be configured in two ways. + +For static images (tag known), can set `prepuller.extraImages` on `applications/jupyterhub/deploy/values.yaml`, like: + +```yaml +prePuller: + extraImages: + nginx-image: + name: nginx + tag: latest +``` + +For images which build is managed by CloudHarness the tag is unknown during the configuration; +for this case, can rely on the dynamic configuration through `harness.jupyterhub.prepull` variable, like: + +```yaml +harness: + jupyterhub: + prepull: + - cloudharness-base +``` + +> Note that only built images defined as tasks, base or common can be used here. +> If an image is not included, it might be required to include it also as a build dependency or, better, define task images directly inside your jupyterhub application override. From 99958b7dbd8ab21ab42addf16909653fc365ec46 Mon Sep 17 00:00:00 2001 From: Zoran Sinnema Date: Mon, 29 Jan 2024 10:57:13 +0100 Subject: [PATCH 08/37] chore(): save jupyterhub profile list in self: --- .../jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py b/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py index fc4d0dd02..ac7dafa66 100644 --- a/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py +++ b/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py @@ -18,6 +18,7 @@ def custom_options_form(spawner, abc): # let's skip the profile selection form for now # ToDo: for future we can remove this hook + spawner._ch_profile_list = spawner.profile_list spawner.profile_list = [] # ref: https://github.com/jupyterhub/kubespawner/blob/37a80abb0a6c826e5c118a068fa1cf2725738038/kubespawner/spawner.py#L1885-L1935 return spawner._options_form_default() From 7126e57da27642aa5db6148692212443e23ed5cf Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 30 Jan 2024 13:34:57 +0100 Subject: [PATCH 09/37] CH-110 fix custom prepull issue --- .../deploy/templates/image-puller/_helpers-daemonset.tpl | 4 ++-- applications/jupyterhub/deploy/values.yaml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl b/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl index f872a3367..04fb18a32 100644 --- a/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl +++ b/applications/jupyterhub/deploy/templates/image-puller/_helpers-daemonset.tpl @@ -201,8 +201,8 @@ spec: {{- end }} {{- end }} {{- /* --- EDIT: CLOUDHARNESS pull images --- */}} - {{- if $.Values.apps.jupyterhub.harness.jupyterhub.prepull -}} - {{- range $k, $v := $.Values.apps.jupyterhub.harness.jupyterhub.prepull }} + {{- if $.Values.apps.jupyterhub.harness.dependencies.prepull -}} + {{- range $k, $v := $.Values.apps.jupyterhub.harness.dependencies.prepull }} - name: image-pull--{{ $v }} image: {{ get ( get $.Values "task-images" ) $v }} command: diff --git a/applications/jupyterhub/deploy/values.yaml b/applications/jupyterhub/deploy/values.yaml index 9be3ad5dd..5acc79282 100755 --- a/applications/jupyterhub/deploy/values.yaml +++ b/applications/jupyterhub/deploy/values.yaml @@ -12,6 +12,7 @@ harness: # EDIT: CLOUDHARNESS - accounts build: - cloudharness-base + prepull: [] # additional images to add to the prepuller quotas: # sets the maximum number of (included named) servers open concurrently (int) quota-ws-open: 3 @@ -31,6 +32,7 @@ harness: # EDIT: CLOUDHARNESS smoketest: true ignoreRequestErrors: false ignoreConsoleErrors: false + # fullnameOverride and nameOverride distinguishes blank strings, null values, # and non-blank strings. For more details, see the configuration reference. From f58f7eddfc370a246f984568a76b0c77d9df45b9 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 29 Jul 2024 15:49:47 +0100 Subject: [PATCH 10/37] CH-91 Updated the harness model to add an envmap deprecating the env property --- .gitignore | 3 +- docs/model/ApiTestsConfig.md | 46 ----- docs/model/ApplicationAccountsConfig.md | 44 ----- docs/model/ApplicationConfig.md | 17 -- docs/model/ApplicationDependenciesConfig.md | 72 -------- docs/model/ApplicationHarnessConfig.md | 93 ---------- docs/model/ApplicationProbe.md | 20 --- docs/model/ApplicationTestConfig.md | 17 -- docs/model/ApplicationUser.md | 44 ----- docs/model/ApplicationsConfigsMap.md | 14 -- docs/model/AutoArtifactSpec.md | 16 -- docs/model/BackupConfig.md | 23 --- docs/model/CDCEvent.md | 21 --- docs/model/CDCEventMeta.md | 33 ---- docs/model/CpuMemoryConfig.md | 16 -- docs/model/DatabaseDeploymentConfig.md | 37 ---- docs/model/DeploymentAutoArtifactConfig.md | 33 ---- docs/model/DeploymentResourcesConf.md | 16 -- docs/model/DeploymentVolumeSpec.md | 33 ---- docs/model/E2ETestsConfig.md | 18 -- docs/model/FileResourcesConfig.md | 17 -- docs/model/Filename.md | 9 - docs/model/FreeObject.md | 14 -- docs/model/GitDependencyConfig.md | 19 -- docs/model/HarnessMainConfig.md | 42 ----- docs/model/IngressConfig.md | 43 ----- docs/model/JupyterHubConfig.md | 32 ---- docs/model/NameValue.md | 16 -- docs/model/PathSpecifier.md | 9 - docs/model/Quota.md | 14 -- docs/model/RegistryConfig.md | 16 -- docs/model/ServiceAutoArtifactConfig.md | 29 ---- docs/model/SimpleMap.md | 14 -- docs/model/URL.md | 9 - docs/model/UnitTestsConfig.md | 30 ---- docs/model/UriRoleMappingConfig.md | 32 ---- docs/model/User.md | 129 -------------- docs/model/UserCredential.md | 23 --- docs/model/UserGroup.md | 82 --------- docs/model/UserRole.md | 33 ---- libraries/models/api/openapi.yaml | 92 +++++----- .../cloudharness_model/models/__init__.py | 8 - .../models/api_tests_config.py | 21 +-- .../models/application_accounts_config.py | 13 +- .../models/application_config.py | 9 +- .../models/application_dependencies_config.py | 21 +-- .../models/application_harness_config.py | 89 +++++----- .../models/application_probe.py | 21 +-- .../models/application_test_config.py | 17 +- .../models/application_user.py | 21 +-- .../models/auto_artifact_spec.py | 13 +- .../models/backup_config.py | 41 ++--- .../cloudharness_model/models/base_model.py | 68 ++++++++ .../cloudharness_model/models/cdc_event.py | 25 ++- .../models/cdc_event_meta.py | 33 ++-- .../models/cpu_memory_config.py | 13 +- .../models/database_deployment_config.py | 163 +++++++++--------- .../models/deployment_auto_artifact_config.py | 147 ++++++++-------- .../models/deployment_resources_conf.py | 13 +- .../models/deployment_volume_spec.py | 139 ++++++++------- .../models/e2_e_tests_config.py | 21 +-- .../models/file_resources_config.py | 17 +- .../models/git_dependency_config.py | 17 +- .../models/harness_main_config.py | 99 +++++++---- .../models/ingress_config.py | 127 +++++++------- .../ingress_config_all_of_letsencrypt.py | 9 +- .../models/jupyter_hub_config.py | 21 +-- .../cloudharness_model/models/name_value.py | 13 +- .../models/registry_config.py | 13 +- .../models/service_auto_artifact_config.py | 75 ++++---- .../models/unit_tests_config.py | 13 +- .../models/uri_role_mapping_config.py | 13 +- .../models/cloudharness_model/models/user.py | 81 +++++---- .../models/user_credential.py | 41 ++--- .../cloudharness_model/models/user_group.py | 37 ++-- .../cloudharness_model/models/user_role.py | 33 ++-- .../models/cloudharness_model/typing_utils.py | 2 - libraries/models/tox.ini | 2 +- 78 files changed, 798 insertions(+), 2031 deletions(-) delete mode 100644 docs/model/ApiTestsConfig.md delete mode 100644 docs/model/ApplicationAccountsConfig.md delete mode 100644 docs/model/ApplicationConfig.md delete mode 100644 docs/model/ApplicationDependenciesConfig.md delete mode 100644 docs/model/ApplicationHarnessConfig.md delete mode 100644 docs/model/ApplicationProbe.md delete mode 100644 docs/model/ApplicationTestConfig.md delete mode 100644 docs/model/ApplicationUser.md delete mode 100644 docs/model/ApplicationsConfigsMap.md delete mode 100644 docs/model/AutoArtifactSpec.md delete mode 100644 docs/model/BackupConfig.md delete mode 100644 docs/model/CDCEvent.md delete mode 100644 docs/model/CDCEventMeta.md delete mode 100644 docs/model/CpuMemoryConfig.md delete mode 100644 docs/model/DatabaseDeploymentConfig.md delete mode 100644 docs/model/DeploymentAutoArtifactConfig.md delete mode 100644 docs/model/DeploymentResourcesConf.md delete mode 100644 docs/model/DeploymentVolumeSpec.md delete mode 100644 docs/model/E2ETestsConfig.md delete mode 100644 docs/model/FileResourcesConfig.md delete mode 100644 docs/model/Filename.md delete mode 100644 docs/model/FreeObject.md delete mode 100644 docs/model/GitDependencyConfig.md delete mode 100644 docs/model/HarnessMainConfig.md delete mode 100644 docs/model/IngressConfig.md delete mode 100644 docs/model/JupyterHubConfig.md delete mode 100644 docs/model/NameValue.md delete mode 100644 docs/model/PathSpecifier.md delete mode 100644 docs/model/Quota.md delete mode 100644 docs/model/RegistryConfig.md delete mode 100644 docs/model/ServiceAutoArtifactConfig.md delete mode 100644 docs/model/SimpleMap.md delete mode 100644 docs/model/URL.md delete mode 100644 docs/model/UnitTestsConfig.md delete mode 100644 docs/model/UriRoleMappingConfig.md delete mode 100644 docs/model/User.md delete mode 100644 docs/model/UserCredential.md delete mode 100644 docs/model/UserGroup.md delete mode 100644 docs/model/UserRole.md create mode 100644 libraries/models/cloudharness_model/models/base_model.py diff --git a/.gitignore b/.gitignore index 90f643c08..774c73153 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ skaffold.yaml /deployment.yaml .hypothesis __pycache__ -.env \ No newline at end of file +.env +/.venv \ No newline at end of file diff --git a/docs/model/ApiTestsConfig.md b/docs/model/ApiTestsConfig.md deleted file mode 100644 index fab49ebca..000000000 --- a/docs/model/ApiTestsConfig.md +++ /dev/null @@ -1,46 +0,0 @@ -# cloudharness_model.model.api_tests_config.ApiTestsConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**[checks](#checks)** | list, tuple, | tuple, | One of the Schemathesis checks: - not_a_server_error. The response has 5xx HTTP status; - status_code_conformance. The response status is not defined in the API schema; - content_type_conformance. The response content type is not defined in the API schema; - response_schema_conformance. The response content does not conform to the schema defined for this specific response; - response_headers_conformance. The response headers does not contain all defined headers. | -**autotest** | bool, | BoolClass, | Specify whether to run the common smoke tests | -**enabled** | bool, | BoolClass, | Enables api tests for this application (default: false) | -**[runParams](#runParams)** | list, tuple, | tuple, | Additional schemathesis parameters | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# checks - -One of the Schemathesis checks: - not_a_server_error. The response has 5xx HTTP status; - status_code_conformance. The response status is not defined in the API schema; - content_type_conformance. The response content type is not defined in the API schema; - response_schema_conformance. The response content does not conform to the schema defined for this specific response; - response_headers_conformance. The response headers does not contain all defined headers. - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | One of the Schemathesis checks: - not_a_server_error. The response has 5xx HTTP status; - status_code_conformance. The response status is not defined in the API schema; - content_type_conformance. The response content type is not defined in the API schema; - response_schema_conformance. The response content does not conform to the schema defined for this specific response; - response_headers_conformance. The response headers does not contain all defined headers. | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# runParams - -Additional schemathesis parameters - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Additional schemathesis parameters | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/ApplicationAccountsConfig.md b/docs/model/ApplicationAccountsConfig.md deleted file mode 100644 index 5cbbdf7d0..000000000 --- a/docs/model/ApplicationAccountsConfig.md +++ /dev/null @@ -1,44 +0,0 @@ -# cloudharness_model.model.application_accounts_config.ApplicationAccountsConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**[roles](#roles)** | list, tuple, | tuple, | Specify roles to be created in this deployment specific for this application | [optional] -**[users](#users)** | list, tuple, | tuple, | Defines test users to be added to the deployment, specific for this application | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# roles - -Specify roles to be created in this deployment specific for this application - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Specify roles to be created in this deployment specific for this application | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# users - -Defines test users to be added to the deployment, specific for this application - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Defines test users to be added to the deployment, specific for this application | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[**ApplicationUser**](ApplicationUser.md) | [**ApplicationUser**](ApplicationUser.md) | [**ApplicationUser**](ApplicationUser.md) | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/ApplicationConfig.md b/docs/model/ApplicationConfig.md deleted file mode 100644 index 667d4b9a5..000000000 --- a/docs/model/ApplicationConfig.md +++ /dev/null @@ -1,17 +0,0 @@ -# cloudharness_model.model.application_config.ApplicationConfig - -Place here the values to configure your application helm templates. - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | Place here the values to configure your application helm templates. | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**harness** | [**ApplicationHarnessConfig**](ApplicationHarnessConfig.md) | [**ApplicationHarnessConfig**](ApplicationHarnessConfig.md) | | -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/ApplicationDependenciesConfig.md b/docs/model/ApplicationDependenciesConfig.md deleted file mode 100644 index a59b2cecc..000000000 --- a/docs/model/ApplicationDependenciesConfig.md +++ /dev/null @@ -1,72 +0,0 @@ -# cloudharness_model.model.application_dependencies_config.ApplicationDependenciesConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**[hard](#hard)** | list, tuple, | tuple, | Hard dependencies indicate that the application may not start without these other applications. | [optional] -**[soft](#soft)** | list, tuple, | tuple, | Soft dependencies indicate that the application will work partially without these other applications. | [optional] -**[build](#build)** | list, tuple, | tuple, | Hard dependencies indicate that the application Docker image build requires these base/common images | [optional] -**[git](#git)** | list, tuple, | tuple, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# hard - -Hard dependencies indicate that the application may not start without these other applications. - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Hard dependencies indicate that the application may not start without these other applications. | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# soft - -Soft dependencies indicate that the application will work partially without these other applications. - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Soft dependencies indicate that the application will work partially without these other applications. | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# build - -Hard dependencies indicate that the application Docker image build requires these base/common images - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Hard dependencies indicate that the application Docker image build requires these base/common images | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# git - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[**GitDependencyConfig**](GitDependencyConfig.md) | [**GitDependencyConfig**](GitDependencyConfig.md) | [**GitDependencyConfig**](GitDependencyConfig.md) | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/ApplicationHarnessConfig.md b/docs/model/ApplicationHarnessConfig.md deleted file mode 100644 index 8e8a251db..000000000 --- a/docs/model/ApplicationHarnessConfig.md +++ /dev/null @@ -1,93 +0,0 @@ -# cloudharness_model.model.application_harness_config.ApplicationHarnessConfig - -Define helm variables that allow CloudHarness to enable and configure your application's deployment - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | Define helm variables that allow CloudHarness to enable and configure your application's deployment | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**deployment** | [**DeploymentAutoArtifactConfig**](DeploymentAutoArtifactConfig.md) | [**DeploymentAutoArtifactConfig**](DeploymentAutoArtifactConfig.md) | | [optional] -**service** | [**ServiceAutoArtifactConfig**](ServiceAutoArtifactConfig.md) | [**ServiceAutoArtifactConfig**](ServiceAutoArtifactConfig.md) | | [optional] -**subdomain** | str, | str, | If specified, an ingress will be created at [subdomain].[.Values.domain] | [optional] -**[aliases](#aliases)** | list, tuple, | tuple, | If specified, an ingress will be created at [alias].[.Values.domain] for each alias | [optional] -**domain** | str, | str, | If specified, an ingress will be created at [domain] | [optional] -**dependencies** | [**ApplicationDependenciesConfig**](ApplicationDependenciesConfig.md) | [**ApplicationDependenciesConfig**](ApplicationDependenciesConfig.md) | | [optional] -**secured** | bool, | BoolClass, | When true, the application is shielded with a getekeeper | [optional] -**[uri_role_mapping](#uri_role_mapping)** | list, tuple, | tuple, | Map uri/roles to secure with the Gatekeeper (if `secured: true`) | [optional] -**secrets** | [**SimpleMap**](SimpleMap.md) | [**SimpleMap**](SimpleMap.md) | | [optional] -**[use_services](#use_services)** | list, tuple, | tuple, | Specify which services this application uses in the frontend to create proxy ingresses. e.g. ``` - name: samples ``` | [optional] -**database** | [**DatabaseDeploymentConfig**](DatabaseDeploymentConfig.md) | [**DatabaseDeploymentConfig**](DatabaseDeploymentConfig.md) | | [optional] -**[resources](#resources)** | list, tuple, | tuple, | Application file resources. Maps from deploy/resources folder and mounts as configmaps | [optional] -**readinessProbe** | [**ApplicationProbe**](ApplicationProbe.md) | [**ApplicationProbe**](ApplicationProbe.md) | | [optional] -**startupProbe** | [**ApplicationProbe**](ApplicationProbe.md) | [**ApplicationProbe**](ApplicationProbe.md) | | [optional] -**livenessProbe** | [**ApplicationProbe**](ApplicationProbe.md) | [**ApplicationProbe**](ApplicationProbe.md) | | [optional] -**sourceRoot** | [**Filename**](Filename.md) | [**Filename**](Filename.md) | | [optional] -**name** | str, | str, | Application's name. Do not edit, the value is automatically set from the application directory's name | [optional] -**jupyterhub** | [**JupyterHubConfig**](JupyterHubConfig.md) | [**JupyterHubConfig**](JupyterHubConfig.md) | | [optional] -**accounts** | [**ApplicationAccountsConfig**](ApplicationAccountsConfig.md) | [**ApplicationAccountsConfig**](ApplicationAccountsConfig.md) | | [optional] -**test** | [**ApplicationTestConfig**](ApplicationTestConfig.md) | [**ApplicationTestConfig**](ApplicationTestConfig.md) | | [optional] -**quotas** | [**Quota**](Quota.md) | [**Quota**](Quota.md) | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# aliases - -If specified, an ingress will be created at [alias].[.Values.domain] for each alias - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | If specified, an ingress will be created at [alias].[.Values.domain] for each alias | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# uri_role_mapping - -Map uri/roles to secure with the Gatekeeper (if `secured: true`) - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Map uri/roles to secure with the Gatekeeper (if `secured: true`) | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[**UriRoleMappingConfig**](UriRoleMappingConfig.md) | [**UriRoleMappingConfig**](UriRoleMappingConfig.md) | [**UriRoleMappingConfig**](UriRoleMappingConfig.md) | | - -# use_services - -Specify which services this application uses in the frontend to create proxy ingresses. e.g. ``` - name: samples ``` - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Specify which services this application uses in the frontend to create proxy ingresses. e.g. ``` - name: samples ``` | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# resources - -Application file resources. Maps from deploy/resources folder and mounts as configmaps - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Application file resources. Maps from deploy/resources folder and mounts as configmaps | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[**FileResourcesConfig**](FileResourcesConfig.md) | [**FileResourcesConfig**](FileResourcesConfig.md) | [**FileResourcesConfig**](FileResourcesConfig.md) | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/ApplicationProbe.md b/docs/model/ApplicationProbe.md deleted file mode 100644 index a3375c463..000000000 --- a/docs/model/ApplicationProbe.md +++ /dev/null @@ -1,20 +0,0 @@ -# cloudharness_model.model.application_probe.ApplicationProbe - -Define a Kubernetes probe See also the [official documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | Define a Kubernetes probe See also the [official documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**path** | str, | str, | | -**periodSeconds** | decimal.Decimal, int, float, | decimal.Decimal, | | [optional] -**failureThreshold** | decimal.Decimal, int, float, | decimal.Decimal, | | [optional] -**initialDelaySeconds** | decimal.Decimal, int, float, | decimal.Decimal, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/ApplicationTestConfig.md b/docs/model/ApplicationTestConfig.md deleted file mode 100644 index 96aced5a3..000000000 --- a/docs/model/ApplicationTestConfig.md +++ /dev/null @@ -1,17 +0,0 @@ -# cloudharness_model.model.application_test_config.ApplicationTestConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**unit** | [**UnitTestsConfig**](UnitTestsConfig.md) | [**UnitTestsConfig**](UnitTestsConfig.md) | | -**e2e** | [**E2ETestsConfig**](E2ETestsConfig.md) | [**E2ETestsConfig**](E2ETestsConfig.md) | | -**api** | [**ApiTestsConfig**](ApiTestsConfig.md) | [**ApiTestsConfig**](ApiTestsConfig.md) | | -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/ApplicationUser.md b/docs/model/ApplicationUser.md deleted file mode 100644 index c55a18e8b..000000000 --- a/docs/model/ApplicationUser.md +++ /dev/null @@ -1,44 +0,0 @@ -# cloudharness_model.model.application_user.ApplicationUser - -Defines a user - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | Defines a user | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**username** | str, | str, | | -**password** | str, | str, | | [optional] -**[clientRoles](#clientRoles)** | list, tuple, | tuple, | | [optional] -**[realmRoles](#realmRoles)** | list, tuple, | tuple, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# clientRoles - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# realmRoles - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/ApplicationsConfigsMap.md b/docs/model/ApplicationsConfigsMap.md deleted file mode 100644 index 7bfc31e5a..000000000 --- a/docs/model/ApplicationsConfigsMap.md +++ /dev/null @@ -1,14 +0,0 @@ -# cloudharness_model.model.applications_configs_map.ApplicationsConfigsMap - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | [**ApplicationConfig**](ApplicationConfig.md) | [**ApplicationConfig**](ApplicationConfig.md) | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/AutoArtifactSpec.md b/docs/model/AutoArtifactSpec.md deleted file mode 100644 index 7d149b703..000000000 --- a/docs/model/AutoArtifactSpec.md +++ /dev/null @@ -1,16 +0,0 @@ -# cloudharness_model.model.auto_artifact_spec.AutoArtifactSpec - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**auto** | bool, | BoolClass, | When true, enables automatic template | -**name** | str, | str, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/BackupConfig.md b/docs/model/BackupConfig.md deleted file mode 100644 index 29cbce3bf..000000000 --- a/docs/model/BackupConfig.md +++ /dev/null @@ -1,23 +0,0 @@ -# cloudharness_model.model.backup_config.BackupConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**resources** | [**DeploymentResourcesConf**](DeploymentResourcesConf.md) | [**DeploymentResourcesConf**](DeploymentResourcesConf.md) | | -**dir** | [**Filename**](Filename.md) | [**Filename**](Filename.md) | | -**active** | bool, | BoolClass, | | [optional] -**keep_days** | decimal.Decimal, int, | decimal.Decimal, | | [optional] -**keep_weeks** | decimal.Decimal, int, | decimal.Decimal, | | [optional] -**keep_months** | decimal.Decimal, int, | decimal.Decimal, | | [optional] -**schedule** | str, | str, | Cron expression | [optional] -**suffix** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | The file suffix added to backup files | [optional] -**volumesize** | str, | str, | The volume size for backups (all backups share the same volume) | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/CDCEvent.md b/docs/model/CDCEvent.md deleted file mode 100644 index c33e10815..000000000 --- a/docs/model/CDCEvent.md +++ /dev/null @@ -1,21 +0,0 @@ -# cloudharness_model.model.cdc_event.CDCEvent - -A message sent to the orchestration queue. Applications can listen to these events to react to data change events happening on other applications. - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | A message sent to the orchestration queue. Applications can listen to these events to react to data change events happening on other applications. | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**uid** | str, | str, | the unique identifier attribute of the object | -**meta** | [**CDCEventMeta**](CDCEventMeta.md) | [**CDCEventMeta**](CDCEventMeta.md) | | -**message_type** | str, | str, | the type of the message (relates to the object type) e.g. jobs | -**operation** | str, | str, | the operation on the object e.g. create / update / delete | must be one of ["create", "update", "delete", "other", ] -**resource** | [**FreeObject**](FreeObject.md) | [**FreeObject**](FreeObject.md) | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/CDCEventMeta.md b/docs/model/CDCEventMeta.md deleted file mode 100644 index 747246d35..000000000 --- a/docs/model/CDCEventMeta.md +++ /dev/null @@ -1,33 +0,0 @@ -# cloudharness_model.model.cdc_event_meta.CDCEventMeta - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**app_name** | str, | str, | The name of the application/microservice sending the message | -**user** | [**User**](User.md) | [**User**](User.md) | | [optional] -**[args](#args)** | list, tuple, | tuple, | the caller function arguments | [optional] -**kwargs** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | the caller function keyword arguments | [optional] -**description** | str, | str, | General description -- for human consumption | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# args - -the caller function arguments - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | the caller function arguments | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[**FreeObject**](FreeObject.md) | [**FreeObject**](FreeObject.md) | [**FreeObject**](FreeObject.md) | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/CpuMemoryConfig.md b/docs/model/CpuMemoryConfig.md deleted file mode 100644 index f64cd7d38..000000000 --- a/docs/model/CpuMemoryConfig.md +++ /dev/null @@ -1,16 +0,0 @@ -# cloudharness_model.model.cpu_memory_config.CpuMemoryConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**cpu** | str, | str, | | [optional] -**memory** | str, | str, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/DatabaseDeploymentConfig.md b/docs/model/DatabaseDeploymentConfig.md deleted file mode 100644 index 864d5ef16..000000000 --- a/docs/model/DatabaseDeploymentConfig.md +++ /dev/null @@ -1,37 +0,0 @@ -# cloudharness_model.model.database_deployment_config.DatabaseDeploymentConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Composed Schemas (allOf/anyOf/oneOf/not) -#### allOf -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[all_of_0](#all_of_0) | dict, frozendict.frozendict, | frozendict.frozendict, | | -[AutoArtifactSpec](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | | - -# all_of_0 - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**type** | str, | str, | Define the database type. One of (mongo, postgres, neo4j, sqlite3) | [optional] -**size** | str, | str, | Specify database disk size | [optional] -**user** | str, | str, | database username | [optional] -**pass** | str, | str, | Database password | [optional] -**image_ref** | str, | str, | Used for referencing images from the build | [optional] -**mongo** | [**FreeObject**](FreeObject.md) | [**FreeObject**](FreeObject.md) | | [optional] -**postgres** | [**FreeObject**](FreeObject.md) | [**FreeObject**](FreeObject.md) | | [optional] -**neo4j** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | Neo4j database specific configuration | [optional] -**resources** | [**DeploymentResourcesConf**](DeploymentResourcesConf.md) | [**DeploymentResourcesConf**](DeploymentResourcesConf.md) | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/DeploymentAutoArtifactConfig.md b/docs/model/DeploymentAutoArtifactConfig.md deleted file mode 100644 index 4367e9493..000000000 --- a/docs/model/DeploymentAutoArtifactConfig.md +++ /dev/null @@ -1,33 +0,0 @@ -# cloudharness_model.model.deployment_auto_artifact_config.DeploymentAutoArtifactConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Composed Schemas (allOf/anyOf/oneOf/not) -#### allOf -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[all_of_0](#all_of_0) | dict, frozendict.frozendict, | frozendict.frozendict, | | -[AutoArtifactSpec](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | | - -# all_of_0 - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**port** | str, | str, | Deployment port | [optional] -**replicas** | decimal.Decimal, int, | decimal.Decimal, | Number of replicas | [optional] -**image** | str, | str, | Image name to use in the deployment. Leave it blank to set from the application's Docker file | [optional] -**resources** | [**DeploymentResourcesConf**](DeploymentResourcesConf.md) | [**DeploymentResourcesConf**](DeploymentResourcesConf.md) | | [optional] -**volume** | [**DeploymentVolumeSpec**](DeploymentVolumeSpec.md) | [**DeploymentVolumeSpec**](DeploymentVolumeSpec.md) | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/DeploymentResourcesConf.md b/docs/model/DeploymentResourcesConf.md deleted file mode 100644 index 6ca517a37..000000000 --- a/docs/model/DeploymentResourcesConf.md +++ /dev/null @@ -1,16 +0,0 @@ -# cloudharness_model.model.deployment_resources_conf.DeploymentResourcesConf - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**requests** | [**CpuMemoryConfig**](CpuMemoryConfig.md) | [**CpuMemoryConfig**](CpuMemoryConfig.md) | | [optional] -**limits** | [**CpuMemoryConfig**](CpuMemoryConfig.md) | [**CpuMemoryConfig**](CpuMemoryConfig.md) | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/DeploymentVolumeSpec.md b/docs/model/DeploymentVolumeSpec.md deleted file mode 100644 index 149001021..000000000 --- a/docs/model/DeploymentVolumeSpec.md +++ /dev/null @@ -1,33 +0,0 @@ -# cloudharness_model.model.deployment_volume_spec.DeploymentVolumeSpec - -Defines a volume attached to the deployment. Automatically created the volume claim and mounts. - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | Defines a volume attached to the deployment. Automatically created the volume claim and mounts. | - -### Composed Schemas (allOf/anyOf/oneOf/not) -#### allOf -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[all_of_0](#all_of_0) | dict, frozendict.frozendict, | frozendict.frozendict, | | -[AutoArtifactSpec](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | | - -# all_of_0 - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**mountpath** | str, | str, | The mount path for the volume | -**size** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | The volume size. E.g. 5Gi | [optional] -**usenfs** | bool, | BoolClass, | Set to `true` to use the nfs on the created volume and mount as ReadWriteMany. | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/E2ETestsConfig.md b/docs/model/E2ETestsConfig.md deleted file mode 100644 index 8b7383d1a..000000000 --- a/docs/model/E2ETestsConfig.md +++ /dev/null @@ -1,18 +0,0 @@ -# cloudharness_model.model.e2_e_tests_config.E2ETestsConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**smoketest** | bool, | BoolClass, | Specify whether to run the common smoke tests | -**enabled** | bool, | BoolClass, | Enables end to end testing for this application (default: false) | -**ignoreConsoleErrors** | bool, | BoolClass, | | [optional] -**ignoreRequestErrors** | bool, | BoolClass, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/FileResourcesConfig.md b/docs/model/FileResourcesConfig.md deleted file mode 100644 index 6936d87c7..000000000 --- a/docs/model/FileResourcesConfig.md +++ /dev/null @@ -1,17 +0,0 @@ -# cloudharness_model.model.file_resources_config.FileResourcesConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**dst** | str, | str, | | -**src** | [**Filename**](Filename.md) | [**Filename**](Filename.md) | | -**name** | [**Filename**](Filename.md) | [**Filename**](Filename.md) | | -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/Filename.md b/docs/model/Filename.md deleted file mode 100644 index ccbf7b0e9..000000000 --- a/docs/model/Filename.md +++ /dev/null @@ -1,9 +0,0 @@ -# cloudharness_model.model.filename.Filename - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -str, | str, | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/FreeObject.md b/docs/model/FreeObject.md deleted file mode 100644 index e131e8469..000000000 --- a/docs/model/FreeObject.md +++ /dev/null @@ -1,14 +0,0 @@ -# cloudharness_model.model.free_object.FreeObject - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/GitDependencyConfig.md b/docs/model/GitDependencyConfig.md deleted file mode 100644 index 5faef2067..000000000 --- a/docs/model/GitDependencyConfig.md +++ /dev/null @@ -1,19 +0,0 @@ -# cloudharness_model.model.git_dependency_config.GitDependencyConfig - -Defines a git repo to be cloned inside the application path - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | Defines a git repo to be cloned inside the application path | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**branch_tag** | str, | str, | | -**url** | str, | str, | | -**path** | str, | str, | Defines the path where the repo is cloned. default: /git | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/HarnessMainConfig.md b/docs/model/HarnessMainConfig.md deleted file mode 100644 index fc0f29dab..000000000 --- a/docs/model/HarnessMainConfig.md +++ /dev/null @@ -1,42 +0,0 @@ -# cloudharness_model.model.harness_main_config.HarnessMainConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**mainapp** | str, | str, | Defines the app to map to the root domain | -**domain** | str, | str, | The root domain | -**namespace** | str, | str, | The K8s namespace. | -**secured_gatekeepers** | bool, | BoolClass, | Enables/disables Gatekeepers on secured applications. Set to false for testing/development | -**local** | bool, | BoolClass, | If set to true, local DNS mapping is added to pods. | -**apps** | [**ApplicationsConfigsMap**](ApplicationsConfigsMap.md) | [**ApplicationsConfigsMap**](ApplicationsConfigsMap.md) | | -**registry** | [**RegistryConfig**](RegistryConfig.md) | [**RegistryConfig**](RegistryConfig.md) | | [optional] -**tag** | str, | str, | Docker tag used to push/pull the built images. | [optional] -**[env](#env)** | list, tuple, | tuple, | Environmental variables added to all pods | [optional] -**privenv** | [**NameValue**](NameValue.md) | [**NameValue**](NameValue.md) | | [optional] -**backup** | [**BackupConfig**](BackupConfig.md) | [**BackupConfig**](BackupConfig.md) | | [optional] -**name** | str, | str, | Base name | [optional] -**task-images** | [**SimpleMap**](SimpleMap.md) | [**SimpleMap**](SimpleMap.md) | | [optional] -**build_hash** | str, | str, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# env - -Environmental variables added to all pods - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Environmental variables added to all pods | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[**NameValue**](NameValue.md) | [**NameValue**](NameValue.md) | [**NameValue**](NameValue.md) | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/IngressConfig.md b/docs/model/IngressConfig.md deleted file mode 100644 index fcdc67eab..000000000 --- a/docs/model/IngressConfig.md +++ /dev/null @@ -1,43 +0,0 @@ -# cloudharness_model.model.ingress_config.IngressConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Composed Schemas (allOf/anyOf/oneOf/not) -#### allOf -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[all_of_0](#all_of_0) | dict, frozendict.frozendict, | frozendict.frozendict, | | -[AutoArtifactSpec](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | | - -# all_of_0 - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**ssl_redirect** | bool, | BoolClass, | | [optional] -**[letsencrypt](#letsencrypt)** | dict, frozendict.frozendict, | frozendict.frozendict, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# letsencrypt - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**email** | str, | str, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/JupyterHubConfig.md b/docs/model/JupyterHubConfig.md deleted file mode 100644 index 59ac9c844..000000000 --- a/docs/model/JupyterHubConfig.md +++ /dev/null @@ -1,32 +0,0 @@ -# cloudharness_model.model.jupyter_hub_config.JupyterHubConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**[args](#args)** | list, tuple, | tuple, | arguments passed to the container | [optional] -**extraConfig** | [**SimpleMap**](SimpleMap.md) | [**SimpleMap**](SimpleMap.md) | | [optional] -**spawnerExtraConfig** | [**FreeObject**](FreeObject.md) | [**FreeObject**](FreeObject.md) | | [optional] -**applicationHook** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | change the hook function (advanced) Specify the Python name of the function (full module path, the module must be installed in the Docker image) | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# args - -arguments passed to the container - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | arguments passed to the container | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/NameValue.md b/docs/model/NameValue.md deleted file mode 100644 index deb575532..000000000 --- a/docs/model/NameValue.md +++ /dev/null @@ -1,16 +0,0 @@ -# cloudharness_model.model.name_value.NameValue - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**name** | str, | str, | | -**value** | str, | str, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/PathSpecifier.md b/docs/model/PathSpecifier.md deleted file mode 100644 index e8062e36a..000000000 --- a/docs/model/PathSpecifier.md +++ /dev/null @@ -1,9 +0,0 @@ -# cloudharness_model.model.path_specifier.PathSpecifier - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -str, | str, | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/Quota.md b/docs/model/Quota.md deleted file mode 100644 index 8124fe928..000000000 --- a/docs/model/Quota.md +++ /dev/null @@ -1,14 +0,0 @@ -# cloudharness_model.model.quota.Quota - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/RegistryConfig.md b/docs/model/RegistryConfig.md deleted file mode 100644 index c63d22b66..000000000 --- a/docs/model/RegistryConfig.md +++ /dev/null @@ -1,16 +0,0 @@ -# cloudharness_model.model.registry_config.RegistryConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**name** | str, | str, | | -**secret** | str, | str, | Optional secret used for pulling from docker registry. | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/ServiceAutoArtifactConfig.md b/docs/model/ServiceAutoArtifactConfig.md deleted file mode 100644 index 6ac6050c4..000000000 --- a/docs/model/ServiceAutoArtifactConfig.md +++ /dev/null @@ -1,29 +0,0 @@ -# cloudharness_model.model.service_auto_artifact_config.ServiceAutoArtifactConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Composed Schemas (allOf/anyOf/oneOf/not) -#### allOf -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[all_of_0](#all_of_0) | dict, frozendict.frozendict, | frozendict.frozendict, | | -[AutoArtifactSpec](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | [**AutoArtifactSpec**](AutoArtifactSpec.md) | | - -# all_of_0 - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**port** | decimal.Decimal, int, | decimal.Decimal, | Service port | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/SimpleMap.md b/docs/model/SimpleMap.md deleted file mode 100644 index 37074b564..000000000 --- a/docs/model/SimpleMap.md +++ /dev/null @@ -1,14 +0,0 @@ -# cloudharness_model.model.simple_map.SimpleMap - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/URL.md b/docs/model/URL.md deleted file mode 100644 index ac2bc6d88..000000000 --- a/docs/model/URL.md +++ /dev/null @@ -1,9 +0,0 @@ -# cloudharness_model.model.url.URL - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -str, | str, | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/UnitTestsConfig.md b/docs/model/UnitTestsConfig.md deleted file mode 100644 index 1c2f16d60..000000000 --- a/docs/model/UnitTestsConfig.md +++ /dev/null @@ -1,30 +0,0 @@ -# cloudharness_model.model.unit_tests_config.UnitTestsConfig - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**[commands](#commands)** | list, tuple, | tuple, | Commands to run unit tests | -**enabled** | bool, | BoolClass, | Enables unit tests for this application (default: true) | -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# commands - -Commands to run unit tests - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Commands to run unit tests | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/UriRoleMappingConfig.md b/docs/model/UriRoleMappingConfig.md deleted file mode 100644 index ff645e734..000000000 --- a/docs/model/UriRoleMappingConfig.md +++ /dev/null @@ -1,32 +0,0 @@ -# cloudharness_model.model.uri_role_mapping_config.UriRoleMappingConfig - -Defines the application Gatekeeper configuration, if enabled (i.e. `secured: true`. - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | Defines the application Gatekeeper configuration, if enabled (i.e. `secured: true`. | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**[roles](#roles)** | list, tuple, | tuple, | Roles allowed to access the present uri | -**uri** | [**PathSpecifier**](PathSpecifier.md) | [**PathSpecifier**](PathSpecifier.md) | | -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# roles - -Roles allowed to access the present uri - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | Roles allowed to access the present uri | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/User.md b/docs/model/User.md deleted file mode 100644 index cd49ceaa1..000000000 --- a/docs/model/User.md +++ /dev/null @@ -1,129 +0,0 @@ -# cloudharness_model.model.user.User - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**[access](#access)** | dict, frozendict.frozendict, | frozendict.frozendict, | | [optional] -**[attributes](#attributes)** | dict, frozendict.frozendict, | frozendict.frozendict, | | [optional] -**[clientRoles](#clientRoles)** | dict, frozendict.frozendict, | frozendict.frozendict, | | [optional] -**createdTimestamp** | decimal.Decimal, int, | decimal.Decimal, | | [optional] value must be a 64 bit integer -**[credentials](#credentials)** | list, tuple, | tuple, | | [optional] -**[disableableCredentialTypes](#disableableCredentialTypes)** | list, tuple, | tuple, | | [optional] -**email** | str, | str, | | [optional] -**emailVerified** | bool, | BoolClass, | | [optional] -**enabled** | bool, | BoolClass, | | [optional] -**federationLink** | str, | str, | | [optional] -**firstName** | str, | str, | | [optional] -**[groups](#groups)** | list, tuple, | tuple, | | [optional] -**id** | str, | str, | | [optional] -**lastName** | str, | str, | | [optional] -**[realmRoles](#realmRoles)** | list, tuple, | tuple, | | [optional] -**[requiredActions](#requiredActions)** | list, tuple, | tuple, | | [optional] -**serviceAccountClientId** | str, | str, | | [optional] -**username** | str, | str, | | [optional] -**additionalProperties** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# access - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# attributes - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# clientRoles - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# credentials - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[**UserCredential**](UserCredential.md) | [**UserCredential**](UserCredential.md) | [**UserCredential**](UserCredential.md) | | - -# disableableCredentialTypes - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# groups - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# realmRoles - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# requiredActions - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/UserCredential.md b/docs/model/UserCredential.md deleted file mode 100644 index d29edc202..000000000 --- a/docs/model/UserCredential.md +++ /dev/null @@ -1,23 +0,0 @@ -# cloudharness_model.model.user_credential.UserCredential - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**createdDate** | decimal.Decimal, int, | decimal.Decimal, | | [optional] value must be a 64 bit integer -**credentialData** | str, | str, | | [optional] -**id** | str, | str, | | [optional] -**priority** | decimal.Decimal, int, | decimal.Decimal, | | [optional] value must be a 32 bit integer -**secretData** | str, | str, | | [optional] -**temporary** | bool, | BoolClass, | | [optional] -**type** | str, | str, | | [optional] -**userLabel** | str, | str, | | [optional] -**value** | str, | str, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/UserGroup.md b/docs/model/UserGroup.md deleted file mode 100644 index 87aee7117..000000000 --- a/docs/model/UserGroup.md +++ /dev/null @@ -1,82 +0,0 @@ -# cloudharness_model.model.user_group.UserGroup - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**[access](#access)** | dict, frozendict.frozendict, | frozendict.frozendict, | | [optional] -**[attributes](#attributes)** | dict, frozendict.frozendict, | frozendict.frozendict, | | [optional] -**[clientRoles](#clientRoles)** | dict, frozendict.frozendict, | frozendict.frozendict, | | [optional] -**id** | str, | str, | | [optional] -**name** | str, | str, | | [optional] -**path** | str, | str, | | [optional] -**[realmRoles](#realmRoles)** | list, tuple, | tuple, | | [optional] -**[subGroups](#subGroups)** | list, tuple, | tuple, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, int, float, bool, decimal.Decimal, None, list, tuple, bytes, io.FileIO, io.BufferedReader | frozendict.frozendict, str, BoolClass, decimal.Decimal, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# access - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# attributes - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# clientRoles - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# realmRoles - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -items | str, | str, | | - -# subGroups - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -list, tuple, | tuple, | | - -### Tuple Items -Class Name | Input Type | Accessed Type | Description | Notes -------------- | ------------- | ------------- | ------------- | ------------- -[**UserGroup**](UserGroup.md) | [**UserGroup**](UserGroup.md) | [**UserGroup**](UserGroup.md) | | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/model/UserRole.md b/docs/model/UserRole.md deleted file mode 100644 index ba0d5fe04..000000000 --- a/docs/model/UserRole.md +++ /dev/null @@ -1,33 +0,0 @@ -# cloudharness_model.model.user_role.UserRole - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**[attributes](#attributes)** | dict, frozendict.frozendict, | frozendict.frozendict, | | [optional] -**clientRole** | bool, | BoolClass, | | [optional] -**composite** | bool, | BoolClass, | | [optional] -**containerId** | str, | str, | | [optional] -**description** | str, | str, | | [optional] -**id** | str, | str, | | [optional] -**name** | str, | str, | | [optional] -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -# attributes - -## Model Type Info -Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- -dict, frozendict.frozendict, | frozendict.frozendict, | | - -### Dictionary Keys -Key | Input Type | Accessed Type | Description | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**any_string_name** | dict, frozendict.frozendict, str, date, datetime, uuid.UUID, int, float, decimal.Decimal, bool, None, list, tuple, bytes, io.FileIO, io.BufferedReader, | frozendict.frozendict, str, decimal.Decimal, BoolClass, NoneClass, tuple, bytes, FileIO | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/libraries/models/api/openapi.yaml b/libraries/models/api/openapi.yaml index 8b961031e..3b115091a 100644 --- a/libraries/models/api/openapi.yaml +++ b/libraries/models/api/openapi.yaml @@ -163,49 +163,6 @@ components: description: '' type: object additionalProperties: true - DatabaseDeploymentConfig: - description: '' - type: object - allOf: - - - type: object - properties: - type: - description: |- - Define the database type. - - One of (mongo, postgres, neo4j, sqlite3) - pattern: ^(mongo|postgres|neo4j|sqlite3)$ - type: string - example: '"neo4j"' - size: - description: Specify database disk size - type: string - example: 1Gi - user: - description: database username - type: string - pass: - format: password - description: Database password - type: string - image_ref: - description: Used for referencing images from the build - type: string - example: 'image_ref: myownpgimage' - mongo: - $ref: '#/components/schemas/FreeObject' - description: Mongo db specific configuration - postgres: - $ref: '#/components/schemas/FreeObject' - description: Postgres database specific configuration - neo4j: - description: Neo4j database specific configuration - resources: - $ref: '#/components/schemas/DeploymentResourcesConf' - description: Database deployment resources - - - $ref: '#/components/schemas/AutoArtifactSpec' ApplicationsConfigsMap: description: '' type: object @@ -823,7 +780,7 @@ components: $ref: '#/components/schemas/ApplicationsConfigsMap' description: '' env: - description: Environmental variables added to all pods + description: 'Environmental variables added to all pods (deprecated, please use envmap)' type: array items: $ref: '#/components/schemas/NameValue' @@ -842,6 +799,9 @@ components: build_hash: description: '' type: string + envmap: + $ref: '#/components/schemas/SimpleMap' + description: Environmental variables added to all pods additionalProperties: true SimpleMap: description: '' @@ -873,3 +833,47 @@ components: url: 'https://github.com/MetaCell/nwb-explorer.git' branch_tag: master path: /git + DatabaseDeploymentConfig: + description: '' + type: object + allOf: + - + type: object + properties: + type: + description: |- + Define the database type. + + One of (mongo, postgres, neo4j, sqlite3) + pattern: ^(mongo|postgres|neo4j|sqlite3)$ + type: string + example: '"neo4j"' + size: + description: Specify database disk size + type: string + example: 1Gi + user: + description: database username + type: string + pass: + format: password + description: Database password + type: string + image_ref: + description: Used for referencing images from the build + type: string + example: 'image_ref: myownpgimage' + mongo: + $ref: '#/components/schemas/FreeObject' + description: Mongo db specific configuration + postgres: + $ref: '#/components/schemas/FreeObject' + description: Postgres database specific configuration + neo4j: + description: Neo4j database specific configuration + resources: + $ref: '#/components/schemas/DeploymentResourcesConf' + description: Database deployment resources + - + $ref: '#/components/schemas/AutoArtifactSpec' + additionalAttributes: true diff --git a/libraries/models/cloudharness_model/models/__init__.py b/libraries/models/cloudharness_model/models/__init__.py index dbfb1175a..488c3e6f6 100644 --- a/libraries/models/cloudharness_model/models/__init__.py +++ b/libraries/models/cloudharness_model/models/__init__.py @@ -1,7 +1,4 @@ -# coding: utf-8 - # flake8: noqa -from __future__ import absolute_import # import models into model package from cloudharness_model.models.api_tests_config import ApiTestsConfig from cloudharness_model.models.application_accounts_config import ApplicationAccountsConfig @@ -17,24 +14,19 @@ from cloudharness_model.models.cdc_event_meta import CDCEventMeta from cloudharness_model.models.cpu_memory_config import CpuMemoryConfig from cloudharness_model.models.database_deployment_config import DatabaseDeploymentConfig -from cloudharness_model.models.database_deployment_config_all_of import DatabaseDeploymentConfigAllOf from cloudharness_model.models.deployment_auto_artifact_config import DeploymentAutoArtifactConfig -from cloudharness_model.models.deployment_auto_artifact_config_all_of import DeploymentAutoArtifactConfigAllOf from cloudharness_model.models.deployment_resources_conf import DeploymentResourcesConf from cloudharness_model.models.deployment_volume_spec import DeploymentVolumeSpec -from cloudharness_model.models.deployment_volume_spec_all_of import DeploymentVolumeSpecAllOf from cloudharness_model.models.e2_e_tests_config import E2ETestsConfig from cloudharness_model.models.file_resources_config import FileResourcesConfig from cloudharness_model.models.git_dependency_config import GitDependencyConfig from cloudharness_model.models.harness_main_config import HarnessMainConfig from cloudharness_model.models.ingress_config import IngressConfig -from cloudharness_model.models.ingress_config_all_of import IngressConfigAllOf from cloudharness_model.models.ingress_config_all_of_letsencrypt import IngressConfigAllOfLetsencrypt from cloudharness_model.models.jupyter_hub_config import JupyterHubConfig from cloudharness_model.models.name_value import NameValue from cloudharness_model.models.registry_config import RegistryConfig from cloudharness_model.models.service_auto_artifact_config import ServiceAutoArtifactConfig -from cloudharness_model.models.service_auto_artifact_config_all_of import ServiceAutoArtifactConfigAllOf from cloudharness_model.models.unit_tests_config import UnitTestsConfig from cloudharness_model.models.uri_role_mapping_config import UriRoleMappingConfig from cloudharness_model.models.user import User diff --git a/libraries/models/cloudharness_model/models/api_tests_config.py b/libraries/models/cloudharness_model/models/api_tests_config.py index d5b2bdf65..a4476c08f 100644 --- a/libraries/models/cloudharness_model/models/api_tests_config.py +++ b/libraries/models/cloudharness_model/models/api_tests_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -58,7 +55,7 @@ def from_dict(cls, dikt) -> 'ApiTestsConfig': return util.deserialize_model(dikt, cls) @property - def enabled(self): + def enabled(self) -> bool: """Gets the enabled of this ApiTestsConfig. Enables api tests for this application (default: false) # noqa: E501 @@ -69,7 +66,7 @@ def enabled(self): return self._enabled @enabled.setter - def enabled(self, enabled): + def enabled(self, enabled: bool): """Sets the enabled of this ApiTestsConfig. Enables api tests for this application (default: false) # noqa: E501 @@ -83,7 +80,7 @@ def enabled(self, enabled): self._enabled = enabled @property - def autotest(self): + def autotest(self) -> bool: """Gets the autotest of this ApiTestsConfig. Specify whether to run the common smoke tests # noqa: E501 @@ -94,7 +91,7 @@ def autotest(self): return self._autotest @autotest.setter - def autotest(self, autotest): + def autotest(self, autotest: bool): """Sets the autotest of this ApiTestsConfig. Specify whether to run the common smoke tests # noqa: E501 @@ -108,7 +105,7 @@ def autotest(self, autotest): self._autotest = autotest @property - def run_params(self): + def run_params(self) -> List[str]: """Gets the run_params of this ApiTestsConfig. Additional schemathesis parameters # noqa: E501 @@ -119,7 +116,7 @@ def run_params(self): return self._run_params @run_params.setter - def run_params(self, run_params): + def run_params(self, run_params: List[str]): """Sets the run_params of this ApiTestsConfig. Additional schemathesis parameters # noqa: E501 @@ -131,7 +128,7 @@ def run_params(self, run_params): self._run_params = run_params @property - def checks(self): + def checks(self) -> List[str]: """Gets the checks of this ApiTestsConfig. One of the Schemathesis checks: - not_a_server_error. The response has 5xx HTTP status; - status_code_conformance. The response status is not defined in the API schema; - content_type_conformance. The response content type is not defined in the API schema; - response_schema_conformance. The response content does not conform to the schema defined for this specific response; - response_headers_conformance. The response headers does not contain all defined headers. # noqa: E501 @@ -142,7 +139,7 @@ def checks(self): return self._checks @checks.setter - def checks(self, checks): + def checks(self, checks: List[str]): """Sets the checks of this ApiTestsConfig. One of the Schemathesis checks: - not_a_server_error. The response has 5xx HTTP status; - status_code_conformance. The response status is not defined in the API schema; - content_type_conformance. The response content type is not defined in the API schema; - response_schema_conformance. The response content does not conform to the schema defined for this specific response; - response_headers_conformance. The response headers does not contain all defined headers. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/application_accounts_config.py b/libraries/models/cloudharness_model/models/application_accounts_config.py index 082f68531..9a97db852 100644 --- a/libraries/models/cloudharness_model/models/application_accounts_config.py +++ b/libraries/models/cloudharness_model/models/application_accounts_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.application_user import ApplicationUser from cloudharness_model import util @@ -50,7 +47,7 @@ def from_dict(cls, dikt) -> 'ApplicationAccountsConfig': return util.deserialize_model(dikt, cls) @property - def roles(self): + def roles(self) -> List[str]: """Gets the roles of this ApplicationAccountsConfig. Specify roles to be created in this deployment specific for this application # noqa: E501 @@ -61,7 +58,7 @@ def roles(self): return self._roles @roles.setter - def roles(self, roles): + def roles(self, roles: List[str]): """Sets the roles of this ApplicationAccountsConfig. Specify roles to be created in this deployment specific for this application # noqa: E501 @@ -73,7 +70,7 @@ def roles(self, roles): self._roles = roles @property - def users(self): + def users(self) -> List[ApplicationUser]: """Gets the users of this ApplicationAccountsConfig. Defines test users to be added to the deployment, specific for this application # noqa: E501 @@ -84,7 +81,7 @@ def users(self): return self._users @users.setter - def users(self, users): + def users(self, users: List[ApplicationUser]): """Sets the users of this ApplicationAccountsConfig. Defines test users to be added to the deployment, specific for this application # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/application_config.py b/libraries/models/cloudharness_model/models/application_config.py index 2ea86d6ed..f423ee3b9 100644 --- a/libraries/models/cloudharness_model/models/application_config.py +++ b/libraries/models/cloudharness_model/models/application_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.application_harness_config import ApplicationHarnessConfig from cloudharness_model import util @@ -45,7 +42,7 @@ def from_dict(cls, dikt) -> 'ApplicationConfig': return util.deserialize_model(dikt, cls) @property - def harness(self): + def harness(self) -> ApplicationHarnessConfig: """Gets the harness of this ApplicationConfig. @@ -55,7 +52,7 @@ def harness(self): return self._harness @harness.setter - def harness(self, harness): + def harness(self, harness: ApplicationHarnessConfig): """Sets the harness of this ApplicationConfig. diff --git a/libraries/models/cloudharness_model/models/application_dependencies_config.py b/libraries/models/cloudharness_model/models/application_dependencies_config.py index 7f4df0bab..a09df86fa 100644 --- a/libraries/models/cloudharness_model/models/application_dependencies_config.py +++ b/libraries/models/cloudharness_model/models/application_dependencies_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.git_dependency_config import GitDependencyConfig from cloudharness_model import util @@ -60,7 +57,7 @@ def from_dict(cls, dikt) -> 'ApplicationDependenciesConfig': return util.deserialize_model(dikt, cls) @property - def hard(self): + def hard(self) -> List[str]: """Gets the hard of this ApplicationDependenciesConfig. Hard dependencies indicate that the application may not start without these other applications. # noqa: E501 @@ -71,7 +68,7 @@ def hard(self): return self._hard @hard.setter - def hard(self, hard): + def hard(self, hard: List[str]): """Sets the hard of this ApplicationDependenciesConfig. Hard dependencies indicate that the application may not start without these other applications. # noqa: E501 @@ -83,7 +80,7 @@ def hard(self, hard): self._hard = hard @property - def soft(self): + def soft(self) -> List[str]: """Gets the soft of this ApplicationDependenciesConfig. Soft dependencies indicate that the application will work partially without these other applications. # noqa: E501 @@ -94,7 +91,7 @@ def soft(self): return self._soft @soft.setter - def soft(self, soft): + def soft(self, soft: List[str]): """Sets the soft of this ApplicationDependenciesConfig. Soft dependencies indicate that the application will work partially without these other applications. # noqa: E501 @@ -106,7 +103,7 @@ def soft(self, soft): self._soft = soft @property - def build(self): + def build(self) -> List[str]: """Gets the build of this ApplicationDependenciesConfig. Hard dependencies indicate that the application Docker image build requires these base/common images # noqa: E501 @@ -117,7 +114,7 @@ def build(self): return self._build @build.setter - def build(self, build): + def build(self, build: List[str]): """Sets the build of this ApplicationDependenciesConfig. Hard dependencies indicate that the application Docker image build requires these base/common images # noqa: E501 @@ -129,7 +126,7 @@ def build(self, build): self._build = build @property - def git(self): + def git(self) -> List[GitDependencyConfig]: """Gets the git of this ApplicationDependenciesConfig. # noqa: E501 @@ -140,7 +137,7 @@ def git(self): return self._git @git.setter - def git(self, git): + def git(self, git: List[GitDependencyConfig]): """Sets the git of this ApplicationDependenciesConfig. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/application_harness_config.py b/libraries/models/cloudharness_model/models/application_harness_config.py index ba2876542..ad85a40bf 100644 --- a/libraries/models/cloudharness_model/models/application_harness_config.py +++ b/libraries/models/cloudharness_model/models/application_harness_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.application_accounts_config import ApplicationAccountsConfig from cloudharness_model.models.application_dependencies_config import ApplicationDependenciesConfig from cloudharness_model.models.application_probe import ApplicationProbe @@ -165,7 +162,7 @@ def from_dict(cls, dikt) -> 'ApplicationHarnessConfig': return util.deserialize_model(dikt, cls) @property - def deployment(self): + def deployment(self) -> DeploymentAutoArtifactConfig: """Gets the deployment of this ApplicationHarnessConfig. @@ -175,7 +172,7 @@ def deployment(self): return self._deployment @deployment.setter - def deployment(self, deployment): + def deployment(self, deployment: DeploymentAutoArtifactConfig): """Sets the deployment of this ApplicationHarnessConfig. @@ -186,7 +183,7 @@ def deployment(self, deployment): self._deployment = deployment @property - def service(self): + def service(self) -> ServiceAutoArtifactConfig: """Gets the service of this ApplicationHarnessConfig. @@ -196,7 +193,7 @@ def service(self): return self._service @service.setter - def service(self, service): + def service(self, service: ServiceAutoArtifactConfig): """Sets the service of this ApplicationHarnessConfig. @@ -207,7 +204,7 @@ def service(self, service): self._service = service @property - def subdomain(self): + def subdomain(self) -> str: """Gets the subdomain of this ApplicationHarnessConfig. If specified, an ingress will be created at [subdomain].[.Values.domain] # noqa: E501 @@ -218,7 +215,7 @@ def subdomain(self): return self._subdomain @subdomain.setter - def subdomain(self, subdomain): + def subdomain(self, subdomain: str): """Sets the subdomain of this ApplicationHarnessConfig. If specified, an ingress will be created at [subdomain].[.Values.domain] # noqa: E501 @@ -230,7 +227,7 @@ def subdomain(self, subdomain): self._subdomain = subdomain @property - def aliases(self): + def aliases(self) -> List[str]: """Gets the aliases of this ApplicationHarnessConfig. If specified, an ingress will be created at [alias].[.Values.domain] for each alias # noqa: E501 @@ -241,7 +238,7 @@ def aliases(self): return self._aliases @aliases.setter - def aliases(self, aliases): + def aliases(self, aliases: List[str]): """Sets the aliases of this ApplicationHarnessConfig. If specified, an ingress will be created at [alias].[.Values.domain] for each alias # noqa: E501 @@ -253,7 +250,7 @@ def aliases(self, aliases): self._aliases = aliases @property - def domain(self): + def domain(self) -> str: """Gets the domain of this ApplicationHarnessConfig. If specified, an ingress will be created at [domain] # noqa: E501 @@ -264,7 +261,7 @@ def domain(self): return self._domain @domain.setter - def domain(self, domain): + def domain(self, domain: str): """Sets the domain of this ApplicationHarnessConfig. If specified, an ingress will be created at [domain] # noqa: E501 @@ -276,7 +273,7 @@ def domain(self, domain): self._domain = domain @property - def dependencies(self): + def dependencies(self) -> ApplicationDependenciesConfig: """Gets the dependencies of this ApplicationHarnessConfig. @@ -286,7 +283,7 @@ def dependencies(self): return self._dependencies @dependencies.setter - def dependencies(self, dependencies): + def dependencies(self, dependencies: ApplicationDependenciesConfig): """Sets the dependencies of this ApplicationHarnessConfig. @@ -297,7 +294,7 @@ def dependencies(self, dependencies): self._dependencies = dependencies @property - def secured(self): + def secured(self) -> bool: """Gets the secured of this ApplicationHarnessConfig. When true, the application is shielded with a getekeeper # noqa: E501 @@ -308,7 +305,7 @@ def secured(self): return self._secured @secured.setter - def secured(self, secured): + def secured(self, secured: bool): """Sets the secured of this ApplicationHarnessConfig. When true, the application is shielded with a getekeeper # noqa: E501 @@ -320,7 +317,7 @@ def secured(self, secured): self._secured = secured @property - def uri_role_mapping(self): + def uri_role_mapping(self) -> List[UriRoleMappingConfig]: """Gets the uri_role_mapping of this ApplicationHarnessConfig. Map uri/roles to secure with the Gatekeeper (if `secured: true`) # noqa: E501 @@ -331,7 +328,7 @@ def uri_role_mapping(self): return self._uri_role_mapping @uri_role_mapping.setter - def uri_role_mapping(self, uri_role_mapping): + def uri_role_mapping(self, uri_role_mapping: List[UriRoleMappingConfig]): """Sets the uri_role_mapping of this ApplicationHarnessConfig. Map uri/roles to secure with the Gatekeeper (if `secured: true`) # noqa: E501 @@ -343,7 +340,7 @@ def uri_role_mapping(self, uri_role_mapping): self._uri_role_mapping = uri_role_mapping @property - def secrets(self): + def secrets(self) -> Dict[str, object]: """Gets the secrets of this ApplicationHarnessConfig. # noqa: E501 @@ -354,7 +351,7 @@ def secrets(self): return self._secrets @secrets.setter - def secrets(self, secrets): + def secrets(self, secrets: Dict[str, object]): """Sets the secrets of this ApplicationHarnessConfig. # noqa: E501 @@ -366,7 +363,7 @@ def secrets(self, secrets): self._secrets = secrets @property - def use_services(self): + def use_services(self) -> List[str]: """Gets the use_services of this ApplicationHarnessConfig. Specify which services this application uses in the frontend to create proxy ingresses. e.g. ``` - name: samples ``` # noqa: E501 @@ -377,7 +374,7 @@ def use_services(self): return self._use_services @use_services.setter - def use_services(self, use_services): + def use_services(self, use_services: List[str]): """Sets the use_services of this ApplicationHarnessConfig. Specify which services this application uses in the frontend to create proxy ingresses. e.g. ``` - name: samples ``` # noqa: E501 @@ -389,7 +386,7 @@ def use_services(self, use_services): self._use_services = use_services @property - def database(self): + def database(self) -> DatabaseDeploymentConfig: """Gets the database of this ApplicationHarnessConfig. @@ -399,7 +396,7 @@ def database(self): return self._database @database.setter - def database(self, database): + def database(self, database: DatabaseDeploymentConfig): """Sets the database of this ApplicationHarnessConfig. @@ -410,7 +407,7 @@ def database(self, database): self._database = database @property - def resources(self): + def resources(self) -> List[FileResourcesConfig]: """Gets the resources of this ApplicationHarnessConfig. Application file resources. Maps from deploy/resources folder and mounts as configmaps # noqa: E501 @@ -421,7 +418,7 @@ def resources(self): return self._resources @resources.setter - def resources(self, resources): + def resources(self, resources: List[FileResourcesConfig]): """Sets the resources of this ApplicationHarnessConfig. Application file resources. Maps from deploy/resources folder and mounts as configmaps # noqa: E501 @@ -433,7 +430,7 @@ def resources(self, resources): self._resources = resources @property - def readiness_probe(self): + def readiness_probe(self) -> ApplicationProbe: """Gets the readiness_probe of this ApplicationHarnessConfig. @@ -443,7 +440,7 @@ def readiness_probe(self): return self._readiness_probe @readiness_probe.setter - def readiness_probe(self, readiness_probe): + def readiness_probe(self, readiness_probe: ApplicationProbe): """Sets the readiness_probe of this ApplicationHarnessConfig. @@ -454,7 +451,7 @@ def readiness_probe(self, readiness_probe): self._readiness_probe = readiness_probe @property - def startup_probe(self): + def startup_probe(self) -> ApplicationProbe: """Gets the startup_probe of this ApplicationHarnessConfig. @@ -464,7 +461,7 @@ def startup_probe(self): return self._startup_probe @startup_probe.setter - def startup_probe(self, startup_probe): + def startup_probe(self, startup_probe: ApplicationProbe): """Sets the startup_probe of this ApplicationHarnessConfig. @@ -475,7 +472,7 @@ def startup_probe(self, startup_probe): self._startup_probe = startup_probe @property - def liveness_probe(self): + def liveness_probe(self) -> ApplicationProbe: """Gets the liveness_probe of this ApplicationHarnessConfig. @@ -485,7 +482,7 @@ def liveness_probe(self): return self._liveness_probe @liveness_probe.setter - def liveness_probe(self, liveness_probe): + def liveness_probe(self, liveness_probe: ApplicationProbe): """Sets the liveness_probe of this ApplicationHarnessConfig. @@ -496,7 +493,7 @@ def liveness_probe(self, liveness_probe): self._liveness_probe = liveness_probe @property - def source_root(self): + def source_root(self) -> str: """Gets the source_root of this ApplicationHarnessConfig. # noqa: E501 @@ -507,7 +504,7 @@ def source_root(self): return self._source_root @source_root.setter - def source_root(self, source_root): + def source_root(self, source_root: str): """Sets the source_root of this ApplicationHarnessConfig. # noqa: E501 @@ -521,7 +518,7 @@ def source_root(self, source_root): self._source_root = source_root @property - def name(self): + def name(self) -> str: """Gets the name of this ApplicationHarnessConfig. Application's name. Do not edit, the value is automatically set from the application directory's name # noqa: E501 @@ -532,7 +529,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this ApplicationHarnessConfig. Application's name. Do not edit, the value is automatically set from the application directory's name # noqa: E501 @@ -544,7 +541,7 @@ def name(self, name): self._name = name @property - def jupyterhub(self): + def jupyterhub(self) -> JupyterHubConfig: """Gets the jupyterhub of this ApplicationHarnessConfig. @@ -554,7 +551,7 @@ def jupyterhub(self): return self._jupyterhub @jupyterhub.setter - def jupyterhub(self, jupyterhub): + def jupyterhub(self, jupyterhub: JupyterHubConfig): """Sets the jupyterhub of this ApplicationHarnessConfig. @@ -565,7 +562,7 @@ def jupyterhub(self, jupyterhub): self._jupyterhub = jupyterhub @property - def accounts(self): + def accounts(self) -> ApplicationAccountsConfig: """Gets the accounts of this ApplicationHarnessConfig. @@ -575,7 +572,7 @@ def accounts(self): return self._accounts @accounts.setter - def accounts(self, accounts): + def accounts(self, accounts: ApplicationAccountsConfig): """Sets the accounts of this ApplicationHarnessConfig. @@ -586,7 +583,7 @@ def accounts(self, accounts): self._accounts = accounts @property - def test(self): + def test(self) -> ApplicationTestConfig: """Gets the test of this ApplicationHarnessConfig. @@ -596,7 +593,7 @@ def test(self): return self._test @test.setter - def test(self, test): + def test(self, test: ApplicationTestConfig): """Sets the test of this ApplicationHarnessConfig. @@ -607,7 +604,7 @@ def test(self, test): self._test = test @property - def quotas(self): + def quotas(self) -> Dict[str, object]: """Gets the quotas of this ApplicationHarnessConfig. # noqa: E501 @@ -618,7 +615,7 @@ def quotas(self): return self._quotas @quotas.setter - def quotas(self, quotas): + def quotas(self, quotas: Dict[str, object]): """Sets the quotas of this ApplicationHarnessConfig. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/application_probe.py b/libraries/models/cloudharness_model/models/application_probe.py index b1819df43..75864acc3 100644 --- a/libraries/models/cloudharness_model/models/application_probe.py +++ b/libraries/models/cloudharness_model/models/application_probe.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -58,7 +55,7 @@ def from_dict(cls, dikt) -> 'ApplicationProbe': return util.deserialize_model(dikt, cls) @property - def path(self): + def path(self) -> str: """Gets the path of this ApplicationProbe. # noqa: E501 @@ -69,7 +66,7 @@ def path(self): return self._path @path.setter - def path(self, path): + def path(self, path: str): """Sets the path of this ApplicationProbe. # noqa: E501 @@ -83,7 +80,7 @@ def path(self, path): self._path = path @property - def period_seconds(self): + def period_seconds(self) -> float: """Gets the period_seconds of this ApplicationProbe. # noqa: E501 @@ -94,7 +91,7 @@ def period_seconds(self): return self._period_seconds @period_seconds.setter - def period_seconds(self, period_seconds): + def period_seconds(self, period_seconds: float): """Sets the period_seconds of this ApplicationProbe. # noqa: E501 @@ -106,7 +103,7 @@ def period_seconds(self, period_seconds): self._period_seconds = period_seconds @property - def failure_threshold(self): + def failure_threshold(self) -> float: """Gets the failure_threshold of this ApplicationProbe. # noqa: E501 @@ -117,7 +114,7 @@ def failure_threshold(self): return self._failure_threshold @failure_threshold.setter - def failure_threshold(self, failure_threshold): + def failure_threshold(self, failure_threshold: float): """Sets the failure_threshold of this ApplicationProbe. # noqa: E501 @@ -129,7 +126,7 @@ def failure_threshold(self, failure_threshold): self._failure_threshold = failure_threshold @property - def initial_delay_seconds(self): + def initial_delay_seconds(self) -> float: """Gets the initial_delay_seconds of this ApplicationProbe. # noqa: E501 @@ -140,7 +137,7 @@ def initial_delay_seconds(self): return self._initial_delay_seconds @initial_delay_seconds.setter - def initial_delay_seconds(self, initial_delay_seconds): + def initial_delay_seconds(self, initial_delay_seconds: float): """Sets the initial_delay_seconds of this ApplicationProbe. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/application_test_config.py b/libraries/models/cloudharness_model/models/application_test_config.py index a9133dd03..3ad315230 100644 --- a/libraries/models/cloudharness_model/models/application_test_config.py +++ b/libraries/models/cloudharness_model/models/application_test_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.api_tests_config import ApiTestsConfig from cloudharness_model.models.e2_e_tests_config import E2ETestsConfig from cloudharness_model.models.unit_tests_config import UnitTestsConfig @@ -59,7 +56,7 @@ def from_dict(cls, dikt) -> 'ApplicationTestConfig': return util.deserialize_model(dikt, cls) @property - def unit(self): + def unit(self) -> UnitTestsConfig: """Gets the unit of this ApplicationTestConfig. @@ -69,7 +66,7 @@ def unit(self): return self._unit @unit.setter - def unit(self, unit): + def unit(self, unit: UnitTestsConfig): """Sets the unit of this ApplicationTestConfig. @@ -82,7 +79,7 @@ def unit(self, unit): self._unit = unit @property - def api(self): + def api(self) -> ApiTestsConfig: """Gets the api of this ApplicationTestConfig. @@ -92,7 +89,7 @@ def api(self): return self._api @api.setter - def api(self, api): + def api(self, api: ApiTestsConfig): """Sets the api of this ApplicationTestConfig. @@ -105,7 +102,7 @@ def api(self, api): self._api = api @property - def e2e(self): + def e2e(self) -> E2ETestsConfig: """Gets the e2e of this ApplicationTestConfig. @@ -115,7 +112,7 @@ def e2e(self): return self._e2e @e2e.setter - def e2e(self, e2e): + def e2e(self, e2e: E2ETestsConfig): """Sets the e2e of this ApplicationTestConfig. diff --git a/libraries/models/cloudharness_model/models/application_user.py b/libraries/models/cloudharness_model/models/application_user.py index 823be12b5..991d8ea37 100644 --- a/libraries/models/cloudharness_model/models/application_user.py +++ b/libraries/models/cloudharness_model/models/application_user.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -58,7 +55,7 @@ def from_dict(cls, dikt) -> 'ApplicationUser': return util.deserialize_model(dikt, cls) @property - def username(self): + def username(self) -> str: """Gets the username of this ApplicationUser. # noqa: E501 @@ -69,7 +66,7 @@ def username(self): return self._username @username.setter - def username(self, username): + def username(self, username: str): """Sets the username of this ApplicationUser. # noqa: E501 @@ -83,7 +80,7 @@ def username(self, username): self._username = username @property - def password(self): + def password(self) -> str: """Gets the password of this ApplicationUser. # noqa: E501 @@ -94,7 +91,7 @@ def password(self): return self._password @password.setter - def password(self, password): + def password(self, password: str): """Sets the password of this ApplicationUser. # noqa: E501 @@ -106,7 +103,7 @@ def password(self, password): self._password = password @property - def client_roles(self): + def client_roles(self) -> List[str]: """Gets the client_roles of this ApplicationUser. # noqa: E501 @@ -117,7 +114,7 @@ def client_roles(self): return self._client_roles @client_roles.setter - def client_roles(self, client_roles): + def client_roles(self, client_roles: List[str]): """Sets the client_roles of this ApplicationUser. # noqa: E501 @@ -129,7 +126,7 @@ def client_roles(self, client_roles): self._client_roles = client_roles @property - def realm_roles(self): + def realm_roles(self) -> List[str]: """Gets the realm_roles of this ApplicationUser. # noqa: E501 @@ -140,7 +137,7 @@ def realm_roles(self): return self._realm_roles @realm_roles.setter - def realm_roles(self, realm_roles): + def realm_roles(self, realm_roles: List[str]): """Sets the realm_roles of this ApplicationUser. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/auto_artifact_spec.py b/libraries/models/cloudharness_model/models/auto_artifact_spec.py index 9aebfd4f9..c0c89ac37 100644 --- a/libraries/models/cloudharness_model/models/auto_artifact_spec.py +++ b/libraries/models/cloudharness_model/models/auto_artifact_spec.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -48,7 +45,7 @@ def from_dict(cls, dikt) -> 'AutoArtifactSpec': return util.deserialize_model(dikt, cls) @property - def auto(self): + def auto(self) -> bool: """Gets the auto of this AutoArtifactSpec. When true, enables automatic template # noqa: E501 @@ -59,7 +56,7 @@ def auto(self): return self._auto @auto.setter - def auto(self, auto): + def auto(self, auto: bool): """Sets the auto of this AutoArtifactSpec. When true, enables automatic template # noqa: E501 @@ -73,7 +70,7 @@ def auto(self, auto): self._auto = auto @property - def name(self): + def name(self) -> str: """Gets the name of this AutoArtifactSpec. # noqa: E501 @@ -84,7 +81,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this AutoArtifactSpec. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/backup_config.py b/libraries/models/cloudharness_model/models/backup_config.py index 254c52f74..0613c70dd 100644 --- a/libraries/models/cloudharness_model/models/backup_config.py +++ b/libraries/models/cloudharness_model/models/backup_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.deployment_resources_conf import DeploymentResourcesConf import re from cloudharness_model import util @@ -87,7 +84,7 @@ def from_dict(cls, dikt) -> 'BackupConfig': return util.deserialize_model(dikt, cls) @property - def active(self): + def active(self) -> bool: """Gets the active of this BackupConfig. # noqa: E501 @@ -98,7 +95,7 @@ def active(self): return self._active @active.setter - def active(self, active): + def active(self, active: bool): """Sets the active of this BackupConfig. # noqa: E501 @@ -110,7 +107,7 @@ def active(self, active): self._active = active @property - def keep_days(self): + def keep_days(self) -> int: """Gets the keep_days of this BackupConfig. # noqa: E501 @@ -121,7 +118,7 @@ def keep_days(self): return self._keep_days @keep_days.setter - def keep_days(self, keep_days): + def keep_days(self, keep_days: int): """Sets the keep_days of this BackupConfig. # noqa: E501 @@ -133,7 +130,7 @@ def keep_days(self, keep_days): self._keep_days = keep_days @property - def keep_weeks(self): + def keep_weeks(self) -> int: """Gets the keep_weeks of this BackupConfig. # noqa: E501 @@ -144,7 +141,7 @@ def keep_weeks(self): return self._keep_weeks @keep_weeks.setter - def keep_weeks(self, keep_weeks): + def keep_weeks(self, keep_weeks: int): """Sets the keep_weeks of this BackupConfig. # noqa: E501 @@ -156,7 +153,7 @@ def keep_weeks(self, keep_weeks): self._keep_weeks = keep_weeks @property - def keep_months(self): + def keep_months(self) -> int: """Gets the keep_months of this BackupConfig. # noqa: E501 @@ -167,7 +164,7 @@ def keep_months(self): return self._keep_months @keep_months.setter - def keep_months(self, keep_months): + def keep_months(self, keep_months: int): """Sets the keep_months of this BackupConfig. # noqa: E501 @@ -179,7 +176,7 @@ def keep_months(self, keep_months): self._keep_months = keep_months @property - def schedule(self): + def schedule(self) -> str: """Gets the schedule of this BackupConfig. Cron expression # noqa: E501 @@ -190,7 +187,7 @@ def schedule(self): return self._schedule @schedule.setter - def schedule(self, schedule): + def schedule(self, schedule: str): """Sets the schedule of this BackupConfig. Cron expression # noqa: E501 @@ -204,7 +201,7 @@ def schedule(self, schedule): self._schedule = schedule @property - def suffix(self): + def suffix(self) -> object: """Gets the suffix of this BackupConfig. The file suffix added to backup files # noqa: E501 @@ -215,7 +212,7 @@ def suffix(self): return self._suffix @suffix.setter - def suffix(self, suffix): + def suffix(self, suffix: object): """Sets the suffix of this BackupConfig. The file suffix added to backup files # noqa: E501 @@ -227,7 +224,7 @@ def suffix(self, suffix): self._suffix = suffix @property - def volumesize(self): + def volumesize(self) -> str: """Gets the volumesize of this BackupConfig. The volume size for backups (all backups share the same volume) # noqa: E501 @@ -238,7 +235,7 @@ def volumesize(self): return self._volumesize @volumesize.setter - def volumesize(self, volumesize): + def volumesize(self, volumesize: str): """Sets the volumesize of this BackupConfig. The volume size for backups (all backups share the same volume) # noqa: E501 @@ -250,7 +247,7 @@ def volumesize(self, volumesize): self._volumesize = volumesize @property - def dir(self): + def dir(self) -> str: """Gets the dir of this BackupConfig. # noqa: E501 @@ -261,7 +258,7 @@ def dir(self): return self._dir @dir.setter - def dir(self, dir): + def dir(self, dir: str): """Sets the dir of this BackupConfig. # noqa: E501 @@ -277,7 +274,7 @@ def dir(self, dir): self._dir = dir @property - def resources(self): + def resources(self) -> DeploymentResourcesConf: """Gets the resources of this BackupConfig. @@ -287,7 +284,7 @@ def resources(self): return self._resources @resources.setter - def resources(self, resources): + def resources(self, resources: DeploymentResourcesConf): """Sets the resources of this BackupConfig. diff --git a/libraries/models/cloudharness_model/models/base_model.py b/libraries/models/cloudharness_model/models/base_model.py new file mode 100644 index 000000000..0938bbc9b --- /dev/null +++ b/libraries/models/cloudharness_model/models/base_model.py @@ -0,0 +1,68 @@ +import pprint + +import typing + +from cloudharness_model import util + +T = typing.TypeVar('T') + + +class Model: + # openapiTypes: The key is attribute name and the + # value is attribute type. + openapi_types: typing.Dict[str, type] = {} + + # attributeMap: The key is attribute name and the + # value is json key in definition. + attribute_map: typing.Dict[str, str] = {} + + @classmethod + def from_dict(cls: typing.Type[T], dikt) -> T: + """Returns the dict as a model""" + return util.deserialize_model(dikt, cls) + + def to_dict(self): + """Returns the model properties as a dict + + :rtype: dict + """ + result = {} + + for attr in self.openapi_types: + value = getattr(self, attr) + if isinstance(value, list): + result[attr] = list(map( + lambda x: x.to_dict() if hasattr(x, "to_dict") else x, + value + )) + elif hasattr(value, "to_dict"): + result[attr] = value.to_dict() + elif isinstance(value, dict): + result[attr] = dict(map( + lambda item: (item[0], item[1].to_dict()) + if hasattr(item[1], "to_dict") else item, + value.items() + )) + else: + result[attr] = value + + return result + + def to_str(self): + """Returns the string representation of the model + + :rtype: str + """ + return pprint.pformat(self.to_dict()) + + def __repr__(self): + """For `print` and `pprint`""" + return self.to_str() + + def __eq__(self, other): + """Returns true if both objects are equal""" + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Returns true if both objects are not equal""" + return not self == other diff --git a/libraries/models/cloudharness_model/models/cdc_event.py b/libraries/models/cloudharness_model/models/cdc_event.py index 1ba4f0179..b8861ad15 100644 --- a/libraries/models/cloudharness_model/models/cdc_event.py +++ b/libraries/models/cloudharness_model/models/cdc_event.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.cdc_event_meta import CDCEventMeta from cloudharness_model import util @@ -65,7 +62,7 @@ def from_dict(cls, dikt) -> 'CDCEvent': return util.deserialize_model(dikt, cls) @property - def operation(self): + def operation(self) -> str: """Gets the operation of this CDCEvent. the operation on the object e.g. create / update / delete # noqa: E501 @@ -76,7 +73,7 @@ def operation(self): return self._operation @operation.setter - def operation(self, operation): + def operation(self, operation: str): """Sets the operation of this CDCEvent. the operation on the object e.g. create / update / delete # noqa: E501 @@ -94,7 +91,7 @@ def operation(self, operation): self._operation = operation @property - def uid(self): + def uid(self) -> str: """Gets the uid of this CDCEvent. the unique identifier attribute of the object # noqa: E501 @@ -105,7 +102,7 @@ def uid(self): return self._uid @uid.setter - def uid(self, uid): + def uid(self, uid: str): """Sets the uid of this CDCEvent. the unique identifier attribute of the object # noqa: E501 @@ -119,7 +116,7 @@ def uid(self, uid): self._uid = uid @property - def message_type(self): + def message_type(self) -> str: """Gets the message_type of this CDCEvent. the type of the message (relates to the object type) e.g. jobs # noqa: E501 @@ -130,7 +127,7 @@ def message_type(self): return self._message_type @message_type.setter - def message_type(self, message_type): + def message_type(self, message_type: str): """Sets the message_type of this CDCEvent. the type of the message (relates to the object type) e.g. jobs # noqa: E501 @@ -144,7 +141,7 @@ def message_type(self, message_type): self._message_type = message_type @property - def resource(self): + def resource(self) -> Dict[str, object]: """Gets the resource of this CDCEvent. # noqa: E501 @@ -155,7 +152,7 @@ def resource(self): return self._resource @resource.setter - def resource(self, resource): + def resource(self, resource: Dict[str, object]): """Sets the resource of this CDCEvent. # noqa: E501 @@ -167,7 +164,7 @@ def resource(self, resource): self._resource = resource @property - def meta(self): + def meta(self) -> CDCEventMeta: """Gets the meta of this CDCEvent. @@ -177,7 +174,7 @@ def meta(self): return self._meta @meta.setter - def meta(self, meta): + def meta(self, meta: CDCEventMeta): """Sets the meta of this CDCEvent. diff --git a/libraries/models/cloudharness_model/models/cdc_event_meta.py b/libraries/models/cloudharness_model/models/cdc_event_meta.py index d88e57d1a..78db4e05f 100644 --- a/libraries/models/cloudharness_model/models/cdc_event_meta.py +++ b/libraries/models/cloudharness_model/models/cdc_event_meta.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.user import User from cloudharness_model import util @@ -25,7 +22,7 @@ def __init__(self, app_name=None, user=None, args=None, kwargs=None, description :param user: The user of this CDCEventMeta. # noqa: E501 :type user: User :param args: The args of this CDCEventMeta. # noqa: E501 - :type args: List[Dict] + :type args: List[Dict[str, object]] :param kwargs: The kwargs of this CDCEventMeta. # noqa: E501 :type kwargs: object :param description: The description of this CDCEventMeta. # noqa: E501 @@ -34,7 +31,7 @@ def __init__(self, app_name=None, user=None, args=None, kwargs=None, description self.openapi_types = { 'app_name': str, 'user': User, - 'args': List[Dict], + 'args': List[Dict[str, object]], 'kwargs': object, 'description': str } @@ -65,7 +62,7 @@ def from_dict(cls, dikt) -> 'CDCEventMeta': return util.deserialize_model(dikt, cls) @property - def app_name(self): + def app_name(self) -> str: """Gets the app_name of this CDCEventMeta. The name of the application/microservice sending the message # noqa: E501 @@ -76,7 +73,7 @@ def app_name(self): return self._app_name @app_name.setter - def app_name(self, app_name): + def app_name(self, app_name: str): """Sets the app_name of this CDCEventMeta. The name of the application/microservice sending the message # noqa: E501 @@ -90,7 +87,7 @@ def app_name(self, app_name): self._app_name = app_name @property - def user(self): + def user(self) -> User: """Gets the user of this CDCEventMeta. @@ -100,7 +97,7 @@ def user(self): return self._user @user.setter - def user(self, user): + def user(self, user: User): """Sets the user of this CDCEventMeta. @@ -111,30 +108,30 @@ def user(self, user): self._user = user @property - def args(self): + def args(self) -> List[Dict[str, object]]: """Gets the args of this CDCEventMeta. the caller function arguments # noqa: E501 :return: The args of this CDCEventMeta. - :rtype: List[Dict] + :rtype: List[Dict[str, object]] """ return self._args @args.setter - def args(self, args): + def args(self, args: List[Dict[str, object]]): """Sets the args of this CDCEventMeta. the caller function arguments # noqa: E501 :param args: The args of this CDCEventMeta. - :type args: List[Dict] + :type args: List[Dict[str, object]] """ self._args = args @property - def kwargs(self): + def kwargs(self) -> object: """Gets the kwargs of this CDCEventMeta. the caller function keyword arguments # noqa: E501 @@ -145,7 +142,7 @@ def kwargs(self): return self._kwargs @kwargs.setter - def kwargs(self, kwargs): + def kwargs(self, kwargs: object): """Sets the kwargs of this CDCEventMeta. the caller function keyword arguments # noqa: E501 @@ -157,7 +154,7 @@ def kwargs(self, kwargs): self._kwargs = kwargs @property - def description(self): + def description(self) -> str: """Gets the description of this CDCEventMeta. General description -- for human consumption # noqa: E501 @@ -168,7 +165,7 @@ def description(self): return self._description @description.setter - def description(self, description): + def description(self, description: str): """Sets the description of this CDCEventMeta. General description -- for human consumption # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/cpu_memory_config.py b/libraries/models/cloudharness_model/models/cpu_memory_config.py index cab9bf7ca..8f4f1e705 100644 --- a/libraries/models/cloudharness_model/models/cpu_memory_config.py +++ b/libraries/models/cloudharness_model/models/cpu_memory_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -48,7 +45,7 @@ def from_dict(cls, dikt) -> 'CpuMemoryConfig': return util.deserialize_model(dikt, cls) @property - def cpu(self): + def cpu(self) -> str: """Gets the cpu of this CpuMemoryConfig. # noqa: E501 @@ -59,7 +56,7 @@ def cpu(self): return self._cpu @cpu.setter - def cpu(self, cpu): + def cpu(self, cpu: str): """Sets the cpu of this CpuMemoryConfig. # noqa: E501 @@ -71,7 +68,7 @@ def cpu(self, cpu): self._cpu = cpu @property - def memory(self): + def memory(self) -> str: """Gets the memory of this CpuMemoryConfig. # noqa: E501 @@ -82,7 +79,7 @@ def memory(self): return self._memory @memory.setter - def memory(self, memory): + def memory(self, memory: str): """Sets the memory of this CpuMemoryConfig. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/database_deployment_config.py b/libraries/models/cloudharness_model/models/database_deployment_config.py index 3786fb899..1be424a20 100644 --- a/libraries/models/cloudharness_model/models/database_deployment_config.py +++ b/libraries/models/cloudharness_model/models/database_deployment_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.deployment_resources_conf import DeploymentResourcesConf import re from cloudharness_model import util @@ -19,9 +16,13 @@ class DatabaseDeploymentConfig(Model): Do not edit the class manually. """ - def __init__(self, type=None, size=None, user=None, _pass=None, image_ref=None, mongo=None, postgres=None, neo4j=None, resources=None, auto=None, name=None): # noqa: E501 + def __init__(self, auto=None, name=None, type=None, size=None, user=None, _pass=None, image_ref=None, mongo=None, postgres=None, neo4j=None, resources=None): # noqa: E501 """DatabaseDeploymentConfig - a model defined in OpenAPI + :param auto: The auto of this DatabaseDeploymentConfig. # noqa: E501 + :type auto: bool + :param name: The name of this DatabaseDeploymentConfig. # noqa: E501 + :type name: str :param type: The type of this DatabaseDeploymentConfig. # noqa: E501 :type type: str :param size: The size of this DatabaseDeploymentConfig. # noqa: E501 @@ -40,12 +41,10 @@ def __init__(self, type=None, size=None, user=None, _pass=None, image_ref=None, :type neo4j: object :param resources: The resources of this DatabaseDeploymentConfig. # noqa: E501 :type resources: DeploymentResourcesConf - :param auto: The auto of this DatabaseDeploymentConfig. # noqa: E501 - :type auto: bool - :param name: The name of this DatabaseDeploymentConfig. # noqa: E501 - :type name: str """ self.openapi_types = { + 'auto': bool, + 'name': str, 'type': str, 'size': str, 'user': str, @@ -54,12 +53,12 @@ def __init__(self, type=None, size=None, user=None, _pass=None, image_ref=None, 'mongo': Dict[str, object], 'postgres': Dict[str, object], 'neo4j': object, - 'resources': DeploymentResourcesConf, - 'auto': bool, - 'name': str + 'resources': DeploymentResourcesConf } self.attribute_map = { + 'auto': 'auto', + 'name': 'name', 'type': 'type', 'size': 'size', 'user': 'user', @@ -68,11 +67,11 @@ def __init__(self, type=None, size=None, user=None, _pass=None, image_ref=None, 'mongo': 'mongo', 'postgres': 'postgres', 'neo4j': 'neo4j', - 'resources': 'resources', - 'auto': 'auto', - 'name': 'name' + 'resources': 'resources' } + self._auto = auto + self._name = name self._type = type self._size = size self._user = user @@ -82,8 +81,6 @@ def __init__(self, type=None, size=None, user=None, _pass=None, image_ref=None, self._postgres = postgres self._neo4j = neo4j self._resources = resources - self._auto = auto - self._name = name @classmethod def from_dict(cls, dikt) -> 'DatabaseDeploymentConfig': @@ -97,7 +94,55 @@ def from_dict(cls, dikt) -> 'DatabaseDeploymentConfig': return util.deserialize_model(dikt, cls) @property - def type(self): + def auto(self) -> bool: + """Gets the auto of this DatabaseDeploymentConfig. + + When true, enables automatic template # noqa: E501 + + :return: The auto of this DatabaseDeploymentConfig. + :rtype: bool + """ + return self._auto + + @auto.setter + def auto(self, auto: bool): + """Sets the auto of this DatabaseDeploymentConfig. + + When true, enables automatic template # noqa: E501 + + :param auto: The auto of this DatabaseDeploymentConfig. + :type auto: bool + """ + if auto is None: + raise ValueError("Invalid value for `auto`, must not be `None`") # noqa: E501 + + self._auto = auto + + @property + def name(self) -> str: + """Gets the name of this DatabaseDeploymentConfig. + + # noqa: E501 + + :return: The name of this DatabaseDeploymentConfig. + :rtype: str + """ + return self._name + + @name.setter + def name(self, name: str): + """Sets the name of this DatabaseDeploymentConfig. + + # noqa: E501 + + :param name: The name of this DatabaseDeploymentConfig. + :type name: str + """ + + self._name = name + + @property + def type(self) -> str: """Gets the type of this DatabaseDeploymentConfig. Define the database type. One of (mongo, postgres, neo4j, sqlite3) # noqa: E501 @@ -108,7 +153,7 @@ def type(self): return self._type @type.setter - def type(self, type): + def type(self, type: str): """Sets the type of this DatabaseDeploymentConfig. Define the database type. One of (mongo, postgres, neo4j, sqlite3) # noqa: E501 @@ -122,7 +167,7 @@ def type(self, type): self._type = type @property - def size(self): + def size(self) -> str: """Gets the size of this DatabaseDeploymentConfig. Specify database disk size # noqa: E501 @@ -133,7 +178,7 @@ def size(self): return self._size @size.setter - def size(self, size): + def size(self, size: str): """Sets the size of this DatabaseDeploymentConfig. Specify database disk size # noqa: E501 @@ -145,7 +190,7 @@ def size(self, size): self._size = size @property - def user(self): + def user(self) -> str: """Gets the user of this DatabaseDeploymentConfig. database username # noqa: E501 @@ -156,7 +201,7 @@ def user(self): return self._user @user.setter - def user(self, user): + def user(self, user: str): """Sets the user of this DatabaseDeploymentConfig. database username # noqa: E501 @@ -168,7 +213,7 @@ def user(self, user): self._user = user @property - def _pass(self): + def _pass(self) -> str: """Gets the _pass of this DatabaseDeploymentConfig. Database password # noqa: E501 @@ -179,7 +224,7 @@ def _pass(self): return self.__pass @_pass.setter - def _pass(self, _pass): + def _pass(self, _pass: str): """Sets the _pass of this DatabaseDeploymentConfig. Database password # noqa: E501 @@ -191,7 +236,7 @@ def _pass(self, _pass): self.__pass = _pass @property - def image_ref(self): + def image_ref(self) -> str: """Gets the image_ref of this DatabaseDeploymentConfig. Used for referencing images from the build # noqa: E501 @@ -202,7 +247,7 @@ def image_ref(self): return self._image_ref @image_ref.setter - def image_ref(self, image_ref): + def image_ref(self, image_ref: str): """Sets the image_ref of this DatabaseDeploymentConfig. Used for referencing images from the build # noqa: E501 @@ -214,7 +259,7 @@ def image_ref(self, image_ref): self._image_ref = image_ref @property - def mongo(self): + def mongo(self) -> Dict[str, object]: """Gets the mongo of this DatabaseDeploymentConfig. # noqa: E501 @@ -225,7 +270,7 @@ def mongo(self): return self._mongo @mongo.setter - def mongo(self, mongo): + def mongo(self, mongo: Dict[str, object]): """Sets the mongo of this DatabaseDeploymentConfig. # noqa: E501 @@ -237,7 +282,7 @@ def mongo(self, mongo): self._mongo = mongo @property - def postgres(self): + def postgres(self) -> Dict[str, object]: """Gets the postgres of this DatabaseDeploymentConfig. # noqa: E501 @@ -248,7 +293,7 @@ def postgres(self): return self._postgres @postgres.setter - def postgres(self, postgres): + def postgres(self, postgres: Dict[str, object]): """Sets the postgres of this DatabaseDeploymentConfig. # noqa: E501 @@ -260,7 +305,7 @@ def postgres(self, postgres): self._postgres = postgres @property - def neo4j(self): + def neo4j(self) -> object: """Gets the neo4j of this DatabaseDeploymentConfig. Neo4j database specific configuration # noqa: E501 @@ -271,7 +316,7 @@ def neo4j(self): return self._neo4j @neo4j.setter - def neo4j(self, neo4j): + def neo4j(self, neo4j: object): """Sets the neo4j of this DatabaseDeploymentConfig. Neo4j database specific configuration # noqa: E501 @@ -283,7 +328,7 @@ def neo4j(self, neo4j): self._neo4j = neo4j @property - def resources(self): + def resources(self) -> DeploymentResourcesConf: """Gets the resources of this DatabaseDeploymentConfig. @@ -293,7 +338,7 @@ def resources(self): return self._resources @resources.setter - def resources(self, resources): + def resources(self, resources: DeploymentResourcesConf): """Sets the resources of this DatabaseDeploymentConfig. @@ -302,51 +347,3 @@ def resources(self, resources): """ self._resources = resources - - @property - def auto(self): - """Gets the auto of this DatabaseDeploymentConfig. - - When true, enables automatic template # noqa: E501 - - :return: The auto of this DatabaseDeploymentConfig. - :rtype: bool - """ - return self._auto - - @auto.setter - def auto(self, auto): - """Sets the auto of this DatabaseDeploymentConfig. - - When true, enables automatic template # noqa: E501 - - :param auto: The auto of this DatabaseDeploymentConfig. - :type auto: bool - """ - if auto is None: - raise ValueError("Invalid value for `auto`, must not be `None`") # noqa: E501 - - self._auto = auto - - @property - def name(self): - """Gets the name of this DatabaseDeploymentConfig. - - # noqa: E501 - - :return: The name of this DatabaseDeploymentConfig. - :rtype: str - """ - return self._name - - @name.setter - def name(self, name): - """Sets the name of this DatabaseDeploymentConfig. - - # noqa: E501 - - :param name: The name of this DatabaseDeploymentConfig. - :type name: str - """ - - self._name = name diff --git a/libraries/models/cloudharness_model/models/deployment_auto_artifact_config.py b/libraries/models/cloudharness_model/models/deployment_auto_artifact_config.py index c72ac4771..ab31de80b 100644 --- a/libraries/models/cloudharness_model/models/deployment_auto_artifact_config.py +++ b/libraries/models/cloudharness_model/models/deployment_auto_artifact_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.deployment_resources_conf import DeploymentResourcesConf from cloudharness_model.models.deployment_volume_spec import DeploymentVolumeSpec import re @@ -21,9 +18,13 @@ class DeploymentAutoArtifactConfig(Model): Do not edit the class manually. """ - def __init__(self, port=None, replicas=None, image=None, resources=None, volume=None, auto=None, name=None): # noqa: E501 + def __init__(self, auto=None, name=None, port=None, replicas=None, image=None, resources=None, volume=None): # noqa: E501 """DeploymentAutoArtifactConfig - a model defined in OpenAPI + :param auto: The auto of this DeploymentAutoArtifactConfig. # noqa: E501 + :type auto: bool + :param name: The name of this DeploymentAutoArtifactConfig. # noqa: E501 + :type name: str :param port: The port of this DeploymentAutoArtifactConfig. # noqa: E501 :type port: str :param replicas: The replicas of this DeploymentAutoArtifactConfig. # noqa: E501 @@ -34,38 +35,34 @@ def __init__(self, port=None, replicas=None, image=None, resources=None, volume= :type resources: DeploymentResourcesConf :param volume: The volume of this DeploymentAutoArtifactConfig. # noqa: E501 :type volume: DeploymentVolumeSpec - :param auto: The auto of this DeploymentAutoArtifactConfig. # noqa: E501 - :type auto: bool - :param name: The name of this DeploymentAutoArtifactConfig. # noqa: E501 - :type name: str """ self.openapi_types = { + 'auto': bool, + 'name': str, 'port': str, 'replicas': int, 'image': str, 'resources': DeploymentResourcesConf, - 'volume': DeploymentVolumeSpec, - 'auto': bool, - 'name': str + 'volume': DeploymentVolumeSpec } self.attribute_map = { + 'auto': 'auto', + 'name': 'name', 'port': 'port', 'replicas': 'replicas', 'image': 'image', 'resources': 'resources', - 'volume': 'volume', - 'auto': 'auto', - 'name': 'name' + 'volume': 'volume' } + self._auto = auto + self._name = name self._port = port self._replicas = replicas self._image = image self._resources = resources self._volume = volume - self._auto = auto - self._name = name @classmethod def from_dict(cls, dikt) -> 'DeploymentAutoArtifactConfig': @@ -79,7 +76,55 @@ def from_dict(cls, dikt) -> 'DeploymentAutoArtifactConfig': return util.deserialize_model(dikt, cls) @property - def port(self): + def auto(self) -> bool: + """Gets the auto of this DeploymentAutoArtifactConfig. + + When true, enables automatic template # noqa: E501 + + :return: The auto of this DeploymentAutoArtifactConfig. + :rtype: bool + """ + return self._auto + + @auto.setter + def auto(self, auto: bool): + """Sets the auto of this DeploymentAutoArtifactConfig. + + When true, enables automatic template # noqa: E501 + + :param auto: The auto of this DeploymentAutoArtifactConfig. + :type auto: bool + """ + if auto is None: + raise ValueError("Invalid value for `auto`, must not be `None`") # noqa: E501 + + self._auto = auto + + @property + def name(self) -> str: + """Gets the name of this DeploymentAutoArtifactConfig. + + # noqa: E501 + + :return: The name of this DeploymentAutoArtifactConfig. + :rtype: str + """ + return self._name + + @name.setter + def name(self, name: str): + """Sets the name of this DeploymentAutoArtifactConfig. + + # noqa: E501 + + :param name: The name of this DeploymentAutoArtifactConfig. + :type name: str + """ + + self._name = name + + @property + def port(self) -> str: """Gets the port of this DeploymentAutoArtifactConfig. Deployment port # noqa: E501 @@ -90,7 +135,7 @@ def port(self): return self._port @port.setter - def port(self, port): + def port(self, port: str): """Sets the port of this DeploymentAutoArtifactConfig. Deployment port # noqa: E501 @@ -102,7 +147,7 @@ def port(self, port): self._port = port @property - def replicas(self): + def replicas(self) -> int: """Gets the replicas of this DeploymentAutoArtifactConfig. Number of replicas # noqa: E501 @@ -113,7 +158,7 @@ def replicas(self): return self._replicas @replicas.setter - def replicas(self, replicas): + def replicas(self, replicas: int): """Sets the replicas of this DeploymentAutoArtifactConfig. Number of replicas # noqa: E501 @@ -125,7 +170,7 @@ def replicas(self, replicas): self._replicas = replicas @property - def image(self): + def image(self) -> str: """Gets the image of this DeploymentAutoArtifactConfig. Image name to use in the deployment. Leave it blank to set from the application's Docker file # noqa: E501 @@ -136,7 +181,7 @@ def image(self): return self._image @image.setter - def image(self, image): + def image(self, image: str): """Sets the image of this DeploymentAutoArtifactConfig. Image name to use in the deployment. Leave it blank to set from the application's Docker file # noqa: E501 @@ -150,7 +195,7 @@ def image(self, image): self._image = image @property - def resources(self): + def resources(self) -> DeploymentResourcesConf: """Gets the resources of this DeploymentAutoArtifactConfig. @@ -160,7 +205,7 @@ def resources(self): return self._resources @resources.setter - def resources(self, resources): + def resources(self, resources: DeploymentResourcesConf): """Sets the resources of this DeploymentAutoArtifactConfig. @@ -171,7 +216,7 @@ def resources(self, resources): self._resources = resources @property - def volume(self): + def volume(self) -> DeploymentVolumeSpec: """Gets the volume of this DeploymentAutoArtifactConfig. @@ -181,7 +226,7 @@ def volume(self): return self._volume @volume.setter - def volume(self, volume): + def volume(self, volume: DeploymentVolumeSpec): """Sets the volume of this DeploymentAutoArtifactConfig. @@ -190,51 +235,3 @@ def volume(self, volume): """ self._volume = volume - - @property - def auto(self): - """Gets the auto of this DeploymentAutoArtifactConfig. - - When true, enables automatic template # noqa: E501 - - :return: The auto of this DeploymentAutoArtifactConfig. - :rtype: bool - """ - return self._auto - - @auto.setter - def auto(self, auto): - """Sets the auto of this DeploymentAutoArtifactConfig. - - When true, enables automatic template # noqa: E501 - - :param auto: The auto of this DeploymentAutoArtifactConfig. - :type auto: bool - """ - if auto is None: - raise ValueError("Invalid value for `auto`, must not be `None`") # noqa: E501 - - self._auto = auto - - @property - def name(self): - """Gets the name of this DeploymentAutoArtifactConfig. - - # noqa: E501 - - :return: The name of this DeploymentAutoArtifactConfig. - :rtype: str - """ - return self._name - - @name.setter - def name(self, name): - """Sets the name of this DeploymentAutoArtifactConfig. - - # noqa: E501 - - :param name: The name of this DeploymentAutoArtifactConfig. - :type name: str - """ - - self._name = name diff --git a/libraries/models/cloudharness_model/models/deployment_resources_conf.py b/libraries/models/cloudharness_model/models/deployment_resources_conf.py index 520e2008e..27c091484 100644 --- a/libraries/models/cloudharness_model/models/deployment_resources_conf.py +++ b/libraries/models/cloudharness_model/models/deployment_resources_conf.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.cpu_memory_config import CpuMemoryConfig from cloudharness_model import util @@ -50,7 +47,7 @@ def from_dict(cls, dikt) -> 'DeploymentResourcesConf': return util.deserialize_model(dikt, cls) @property - def requests(self): + def requests(self) -> CpuMemoryConfig: """Gets the requests of this DeploymentResourcesConf. @@ -60,7 +57,7 @@ def requests(self): return self._requests @requests.setter - def requests(self, requests): + def requests(self, requests: CpuMemoryConfig): """Sets the requests of this DeploymentResourcesConf. @@ -71,7 +68,7 @@ def requests(self, requests): self._requests = requests @property - def limits(self): + def limits(self) -> CpuMemoryConfig: """Gets the limits of this DeploymentResourcesConf. @@ -81,7 +78,7 @@ def limits(self): return self._limits @limits.setter - def limits(self, limits): + def limits(self, limits: CpuMemoryConfig): """Sets the limits of this DeploymentResourcesConf. diff --git a/libraries/models/cloudharness_model/models/deployment_volume_spec.py b/libraries/models/cloudharness_model/models/deployment_volume_spec.py index 631bc55d9..7fc64914a 100644 --- a/libraries/models/cloudharness_model/models/deployment_volume_spec.py +++ b/libraries/models/cloudharness_model/models/deployment_volume_spec.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -15,41 +12,41 @@ class DeploymentVolumeSpec(Model): Do not edit the class manually. """ - def __init__(self, mountpath=None, size=None, usenfs=None, auto=None, name=None): # noqa: E501 + def __init__(self, auto=None, name=None, mountpath=None, size=None, usenfs=None): # noqa: E501 """DeploymentVolumeSpec - a model defined in OpenAPI + :param auto: The auto of this DeploymentVolumeSpec. # noqa: E501 + :type auto: bool + :param name: The name of this DeploymentVolumeSpec. # noqa: E501 + :type name: str :param mountpath: The mountpath of this DeploymentVolumeSpec. # noqa: E501 :type mountpath: str :param size: The size of this DeploymentVolumeSpec. # noqa: E501 :type size: object :param usenfs: The usenfs of this DeploymentVolumeSpec. # noqa: E501 :type usenfs: bool - :param auto: The auto of this DeploymentVolumeSpec. # noqa: E501 - :type auto: bool - :param name: The name of this DeploymentVolumeSpec. # noqa: E501 - :type name: str """ self.openapi_types = { + 'auto': bool, + 'name': str, 'mountpath': str, 'size': object, - 'usenfs': bool, - 'auto': bool, - 'name': str + 'usenfs': bool } self.attribute_map = { + 'auto': 'auto', + 'name': 'name', 'mountpath': 'mountpath', 'size': 'size', - 'usenfs': 'usenfs', - 'auto': 'auto', - 'name': 'name' + 'usenfs': 'usenfs' } + self._auto = auto + self._name = name self._mountpath = mountpath self._size = size self._usenfs = usenfs - self._auto = auto - self._name = name @classmethod def from_dict(cls, dikt) -> 'DeploymentVolumeSpec': @@ -63,7 +60,55 @@ def from_dict(cls, dikt) -> 'DeploymentVolumeSpec': return util.deserialize_model(dikt, cls) @property - def mountpath(self): + def auto(self) -> bool: + """Gets the auto of this DeploymentVolumeSpec. + + When true, enables automatic template # noqa: E501 + + :return: The auto of this DeploymentVolumeSpec. + :rtype: bool + """ + return self._auto + + @auto.setter + def auto(self, auto: bool): + """Sets the auto of this DeploymentVolumeSpec. + + When true, enables automatic template # noqa: E501 + + :param auto: The auto of this DeploymentVolumeSpec. + :type auto: bool + """ + if auto is None: + raise ValueError("Invalid value for `auto`, must not be `None`") # noqa: E501 + + self._auto = auto + + @property + def name(self) -> str: + """Gets the name of this DeploymentVolumeSpec. + + # noqa: E501 + + :return: The name of this DeploymentVolumeSpec. + :rtype: str + """ + return self._name + + @name.setter + def name(self, name: str): + """Sets the name of this DeploymentVolumeSpec. + + # noqa: E501 + + :param name: The name of this DeploymentVolumeSpec. + :type name: str + """ + + self._name = name + + @property + def mountpath(self) -> str: """Gets the mountpath of this DeploymentVolumeSpec. The mount path for the volume # noqa: E501 @@ -74,7 +119,7 @@ def mountpath(self): return self._mountpath @mountpath.setter - def mountpath(self, mountpath): + def mountpath(self, mountpath: str): """Sets the mountpath of this DeploymentVolumeSpec. The mount path for the volume # noqa: E501 @@ -88,7 +133,7 @@ def mountpath(self, mountpath): self._mountpath = mountpath @property - def size(self): + def size(self) -> object: """Gets the size of this DeploymentVolumeSpec. The volume size. E.g. 5Gi # noqa: E501 @@ -99,7 +144,7 @@ def size(self): return self._size @size.setter - def size(self, size): + def size(self, size: object): """Sets the size of this DeploymentVolumeSpec. The volume size. E.g. 5Gi # noqa: E501 @@ -111,7 +156,7 @@ def size(self, size): self._size = size @property - def usenfs(self): + def usenfs(self) -> bool: """Gets the usenfs of this DeploymentVolumeSpec. Set to `true` to use the nfs on the created volume and mount as ReadWriteMany. # noqa: E501 @@ -122,7 +167,7 @@ def usenfs(self): return self._usenfs @usenfs.setter - def usenfs(self, usenfs): + def usenfs(self, usenfs: bool): """Sets the usenfs of this DeploymentVolumeSpec. Set to `true` to use the nfs on the created volume and mount as ReadWriteMany. # noqa: E501 @@ -132,51 +177,3 @@ def usenfs(self, usenfs): """ self._usenfs = usenfs - - @property - def auto(self): - """Gets the auto of this DeploymentVolumeSpec. - - When true, enables automatic template # noqa: E501 - - :return: The auto of this DeploymentVolumeSpec. - :rtype: bool - """ - return self._auto - - @auto.setter - def auto(self, auto): - """Sets the auto of this DeploymentVolumeSpec. - - When true, enables automatic template # noqa: E501 - - :param auto: The auto of this DeploymentVolumeSpec. - :type auto: bool - """ - if auto is None: - raise ValueError("Invalid value for `auto`, must not be `None`") # noqa: E501 - - self._auto = auto - - @property - def name(self): - """Gets the name of this DeploymentVolumeSpec. - - # noqa: E501 - - :return: The name of this DeploymentVolumeSpec. - :rtype: str - """ - return self._name - - @name.setter - def name(self, name): - """Sets the name of this DeploymentVolumeSpec. - - # noqa: E501 - - :param name: The name of this DeploymentVolumeSpec. - :type name: str - """ - - self._name = name diff --git a/libraries/models/cloudharness_model/models/e2_e_tests_config.py b/libraries/models/cloudharness_model/models/e2_e_tests_config.py index e856fe9dc..6ae48d93f 100644 --- a/libraries/models/cloudharness_model/models/e2_e_tests_config.py +++ b/libraries/models/cloudharness_model/models/e2_e_tests_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -58,7 +55,7 @@ def from_dict(cls, dikt) -> 'E2ETestsConfig': return util.deserialize_model(dikt, cls) @property - def enabled(self): + def enabled(self) -> bool: """Gets the enabled of this E2ETestsConfig. Enables end to end testing for this application (default: false) # noqa: E501 @@ -69,7 +66,7 @@ def enabled(self): return self._enabled @enabled.setter - def enabled(self, enabled): + def enabled(self, enabled: bool): """Sets the enabled of this E2ETestsConfig. Enables end to end testing for this application (default: false) # noqa: E501 @@ -83,7 +80,7 @@ def enabled(self, enabled): self._enabled = enabled @property - def smoketest(self): + def smoketest(self) -> bool: """Gets the smoketest of this E2ETestsConfig. Specify whether to run the common smoke tests # noqa: E501 @@ -94,7 +91,7 @@ def smoketest(self): return self._smoketest @smoketest.setter - def smoketest(self, smoketest): + def smoketest(self, smoketest: bool): """Sets the smoketest of this E2ETestsConfig. Specify whether to run the common smoke tests # noqa: E501 @@ -108,7 +105,7 @@ def smoketest(self, smoketest): self._smoketest = smoketest @property - def ignore_console_errors(self): + def ignore_console_errors(self) -> bool: """Gets the ignore_console_errors of this E2ETestsConfig. # noqa: E501 @@ -119,7 +116,7 @@ def ignore_console_errors(self): return self._ignore_console_errors @ignore_console_errors.setter - def ignore_console_errors(self, ignore_console_errors): + def ignore_console_errors(self, ignore_console_errors: bool): """Sets the ignore_console_errors of this E2ETestsConfig. # noqa: E501 @@ -131,7 +128,7 @@ def ignore_console_errors(self, ignore_console_errors): self._ignore_console_errors = ignore_console_errors @property - def ignore_request_errors(self): + def ignore_request_errors(self) -> bool: """Gets the ignore_request_errors of this E2ETestsConfig. # noqa: E501 @@ -142,7 +139,7 @@ def ignore_request_errors(self): return self._ignore_request_errors @ignore_request_errors.setter - def ignore_request_errors(self, ignore_request_errors): + def ignore_request_errors(self, ignore_request_errors: bool): """Sets the ignore_request_errors of this E2ETestsConfig. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/file_resources_config.py b/libraries/models/cloudharness_model/models/file_resources_config.py index da5993b41..fff73422d 100644 --- a/libraries/models/cloudharness_model/models/file_resources_config.py +++ b/libraries/models/cloudharness_model/models/file_resources_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model import re from cloudharness_model import util @@ -55,7 +52,7 @@ def from_dict(cls, dikt) -> 'FileResourcesConfig': return util.deserialize_model(dikt, cls) @property - def name(self): + def name(self) -> str: """Gets the name of this FileResourcesConfig. # noqa: E501 @@ -66,7 +63,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this FileResourcesConfig. # noqa: E501 @@ -82,7 +79,7 @@ def name(self, name): self._name = name @property - def src(self): + def src(self) -> str: """Gets the src of this FileResourcesConfig. # noqa: E501 @@ -93,7 +90,7 @@ def src(self): return self._src @src.setter - def src(self, src): + def src(self, src: str): """Sets the src of this FileResourcesConfig. # noqa: E501 @@ -109,7 +106,7 @@ def src(self, src): self._src = src @property - def dst(self): + def dst(self) -> str: """Gets the dst of this FileResourcesConfig. # noqa: E501 @@ -120,7 +117,7 @@ def dst(self): return self._dst @dst.setter - def dst(self, dst): + def dst(self, dst: str): """Sets the dst of this FileResourcesConfig. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/git_dependency_config.py b/libraries/models/cloudharness_model/models/git_dependency_config.py index b2a176909..8e3acf613 100644 --- a/libraries/models/cloudharness_model/models/git_dependency_config.py +++ b/libraries/models/cloudharness_model/models/git_dependency_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -53,7 +50,7 @@ def from_dict(cls, dikt) -> 'GitDependencyConfig': return util.deserialize_model(dikt, cls) @property - def url(self): + def url(self) -> str: """Gets the url of this GitDependencyConfig. @@ -63,7 +60,7 @@ def url(self): return self._url @url.setter - def url(self, url): + def url(self, url: str): """Sets the url of this GitDependencyConfig. @@ -76,7 +73,7 @@ def url(self, url): self._url = url @property - def branch_tag(self): + def branch_tag(self) -> str: """Gets the branch_tag of this GitDependencyConfig. @@ -86,7 +83,7 @@ def branch_tag(self): return self._branch_tag @branch_tag.setter - def branch_tag(self, branch_tag): + def branch_tag(self, branch_tag: str): """Sets the branch_tag of this GitDependencyConfig. @@ -99,7 +96,7 @@ def branch_tag(self, branch_tag): self._branch_tag = branch_tag @property - def path(self): + def path(self) -> str: """Gets the path of this GitDependencyConfig. Defines the path where the repo is cloned. default: /git # noqa: E501 @@ -110,7 +107,7 @@ def path(self): return self._path @path.setter - def path(self, path): + def path(self, path: str): """Sets the path of this GitDependencyConfig. Defines the path where the repo is cloned. default: /git # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/harness_main_config.py b/libraries/models/cloudharness_model/models/harness_main_config.py index 7f18e82d1..6691ed073 100644 --- a/libraries/models/cloudharness_model/models/harness_main_config.py +++ b/libraries/models/cloudharness_model/models/harness_main_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.application_config import ApplicationConfig from cloudharness_model.models.backup_config import BackupConfig from cloudharness_model.models.name_value import NameValue @@ -23,7 +20,7 @@ class HarnessMainConfig(Model): Do not edit the class manually. """ - def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace=None, mainapp=None, registry=None, tag=None, apps=None, env=None, privenv=None, backup=None, name=None, task_images=None, build_hash=None): # noqa: E501 + def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace=None, mainapp=None, registry=None, tag=None, apps=None, env=None, privenv=None, backup=None, name=None, task_images=None, build_hash=None, envmap=None): # noqa: E501 """HarnessMainConfig - a model defined in OpenAPI :param local: The local of this HarnessMainConfig. # noqa: E501 @@ -54,6 +51,8 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= :type task_images: Dict[str, object] :param build_hash: The build_hash of this HarnessMainConfig. # noqa: E501 :type build_hash: str + :param envmap: The envmap of this HarnessMainConfig. # noqa: E501 + :type envmap: Dict[str, object] """ self.openapi_types = { 'local': bool, @@ -69,7 +68,8 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= 'backup': BackupConfig, 'name': str, 'task_images': Dict[str, object], - 'build_hash': str + 'build_hash': str, + 'envmap': Dict[str, object] } self.attribute_map = { @@ -86,7 +86,8 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= 'backup': 'backup', 'name': 'name', 'task_images': 'task-images', - 'build_hash': 'build_hash' + 'build_hash': 'build_hash', + 'envmap': 'envmap' } self._local = local @@ -103,6 +104,7 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= self._name = name self._task_images = task_images self._build_hash = build_hash + self._envmap = envmap @classmethod def from_dict(cls, dikt) -> 'HarnessMainConfig': @@ -116,7 +118,7 @@ def from_dict(cls, dikt) -> 'HarnessMainConfig': return util.deserialize_model(dikt, cls) @property - def local(self): + def local(self) -> bool: """Gets the local of this HarnessMainConfig. If set to true, local DNS mapping is added to pods. # noqa: E501 @@ -127,7 +129,7 @@ def local(self): return self._local @local.setter - def local(self, local): + def local(self, local: bool): """Sets the local of this HarnessMainConfig. If set to true, local DNS mapping is added to pods. # noqa: E501 @@ -141,7 +143,7 @@ def local(self, local): self._local = local @property - def secured_gatekeepers(self): + def secured_gatekeepers(self) -> bool: """Gets the secured_gatekeepers of this HarnessMainConfig. Enables/disables Gatekeepers on secured applications. Set to false for testing/development # noqa: E501 @@ -152,7 +154,7 @@ def secured_gatekeepers(self): return self._secured_gatekeepers @secured_gatekeepers.setter - def secured_gatekeepers(self, secured_gatekeepers): + def secured_gatekeepers(self, secured_gatekeepers: bool): """Sets the secured_gatekeepers of this HarnessMainConfig. Enables/disables Gatekeepers on secured applications. Set to false for testing/development # noqa: E501 @@ -166,7 +168,7 @@ def secured_gatekeepers(self, secured_gatekeepers): self._secured_gatekeepers = secured_gatekeepers @property - def domain(self): + def domain(self) -> str: """Gets the domain of this HarnessMainConfig. The root domain # noqa: E501 @@ -177,7 +179,7 @@ def domain(self): return self._domain @domain.setter - def domain(self, domain): + def domain(self, domain: str): """Sets the domain of this HarnessMainConfig. The root domain # noqa: E501 @@ -191,7 +193,7 @@ def domain(self, domain): self._domain = domain @property - def namespace(self): + def namespace(self) -> str: """Gets the namespace of this HarnessMainConfig. The K8s namespace. # noqa: E501 @@ -202,7 +204,7 @@ def namespace(self): return self._namespace @namespace.setter - def namespace(self, namespace): + def namespace(self, namespace: str): """Sets the namespace of this HarnessMainConfig. The K8s namespace. # noqa: E501 @@ -216,7 +218,7 @@ def namespace(self, namespace): self._namespace = namespace @property - def mainapp(self): + def mainapp(self) -> str: """Gets the mainapp of this HarnessMainConfig. Defines the app to map to the root domain # noqa: E501 @@ -227,7 +229,7 @@ def mainapp(self): return self._mainapp @mainapp.setter - def mainapp(self, mainapp): + def mainapp(self, mainapp: str): """Sets the mainapp of this HarnessMainConfig. Defines the app to map to the root domain # noqa: E501 @@ -241,7 +243,7 @@ def mainapp(self, mainapp): self._mainapp = mainapp @property - def registry(self): + def registry(self) -> RegistryConfig: """Gets the registry of this HarnessMainConfig. @@ -251,7 +253,7 @@ def registry(self): return self._registry @registry.setter - def registry(self, registry): + def registry(self, registry: RegistryConfig): """Sets the registry of this HarnessMainConfig. @@ -262,7 +264,7 @@ def registry(self, registry): self._registry = registry @property - def tag(self): + def tag(self) -> str: """Gets the tag of this HarnessMainConfig. Docker tag used to push/pull the built images. # noqa: E501 @@ -273,7 +275,7 @@ def tag(self): return self._tag @tag.setter - def tag(self, tag): + def tag(self, tag: str): """Sets the tag of this HarnessMainConfig. Docker tag used to push/pull the built images. # noqa: E501 @@ -285,7 +287,7 @@ def tag(self, tag): self._tag = tag @property - def apps(self): + def apps(self) -> Dict[str, ApplicationConfig]: """Gets the apps of this HarnessMainConfig. # noqa: E501 @@ -296,7 +298,7 @@ def apps(self): return self._apps @apps.setter - def apps(self, apps): + def apps(self, apps: Dict[str, ApplicationConfig]): """Sets the apps of this HarnessMainConfig. # noqa: E501 @@ -310,10 +312,10 @@ def apps(self, apps): self._apps = apps @property - def env(self): + def env(self) -> List[NameValue]: """Gets the env of this HarnessMainConfig. - Environmental variables added to all pods # noqa: E501 + Environmental variables added to all pods (deprecated, please use envmap) # noqa: E501 :return: The env of this HarnessMainConfig. :rtype: List[NameValue] @@ -321,10 +323,10 @@ def env(self): return self._env @env.setter - def env(self, env): + def env(self, env: List[NameValue]): """Sets the env of this HarnessMainConfig. - Environmental variables added to all pods # noqa: E501 + Environmental variables added to all pods (deprecated, please use envmap) # noqa: E501 :param env: The env of this HarnessMainConfig. :type env: List[NameValue] @@ -333,7 +335,7 @@ def env(self, env): self._env = env @property - def privenv(self): + def privenv(self) -> NameValue: """Gets the privenv of this HarnessMainConfig. @@ -343,7 +345,7 @@ def privenv(self): return self._privenv @privenv.setter - def privenv(self, privenv): + def privenv(self, privenv: NameValue): """Sets the privenv of this HarnessMainConfig. @@ -354,7 +356,7 @@ def privenv(self, privenv): self._privenv = privenv @property - def backup(self): + def backup(self) -> BackupConfig: """Gets the backup of this HarnessMainConfig. @@ -364,7 +366,7 @@ def backup(self): return self._backup @backup.setter - def backup(self, backup): + def backup(self, backup: BackupConfig): """Sets the backup of this HarnessMainConfig. @@ -375,7 +377,7 @@ def backup(self, backup): self._backup = backup @property - def name(self): + def name(self) -> str: """Gets the name of this HarnessMainConfig. Base name # noqa: E501 @@ -386,7 +388,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this HarnessMainConfig. Base name # noqa: E501 @@ -398,7 +400,7 @@ def name(self, name): self._name = name @property - def task_images(self): + def task_images(self) -> Dict[str, object]: """Gets the task_images of this HarnessMainConfig. # noqa: E501 @@ -409,7 +411,7 @@ def task_images(self): return self._task_images @task_images.setter - def task_images(self, task_images): + def task_images(self, task_images: Dict[str, object]): """Sets the task_images of this HarnessMainConfig. # noqa: E501 @@ -421,7 +423,7 @@ def task_images(self, task_images): self._task_images = task_images @property - def build_hash(self): + def build_hash(self) -> str: """Gets the build_hash of this HarnessMainConfig. # noqa: E501 @@ -432,7 +434,7 @@ def build_hash(self): return self._build_hash @build_hash.setter - def build_hash(self, build_hash): + def build_hash(self, build_hash: str): """Sets the build_hash of this HarnessMainConfig. # noqa: E501 @@ -442,3 +444,26 @@ def build_hash(self, build_hash): """ self._build_hash = build_hash + + @property + def envmap(self) -> Dict[str, object]: + """Gets the envmap of this HarnessMainConfig. + + # noqa: E501 + + :return: The envmap of this HarnessMainConfig. + :rtype: Dict[str, object] + """ + return self._envmap + + @envmap.setter + def envmap(self, envmap: Dict[str, object]): + """Sets the envmap of this HarnessMainConfig. + + # noqa: E501 + + :param envmap: The envmap of this HarnessMainConfig. + :type envmap: Dict[str, object] + """ + + self._envmap = envmap diff --git a/libraries/models/cloudharness_model/models/ingress_config.py b/libraries/models/cloudharness_model/models/ingress_config.py index 6253941ae..e0da288f0 100644 --- a/libraries/models/cloudharness_model/models/ingress_config.py +++ b/libraries/models/cloudharness_model/models/ingress_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.ingress_config_all_of_letsencrypt import IngressConfigAllOfLetsencrypt from cloudharness_model import util @@ -17,36 +14,36 @@ class IngressConfig(Model): Do not edit the class manually. """ - def __init__(self, ssl_redirect=None, letsencrypt=None, auto=None, name=None): # noqa: E501 + def __init__(self, auto=None, name=None, ssl_redirect=None, letsencrypt=None): # noqa: E501 """IngressConfig - a model defined in OpenAPI - :param ssl_redirect: The ssl_redirect of this IngressConfig. # noqa: E501 - :type ssl_redirect: bool - :param letsencrypt: The letsencrypt of this IngressConfig. # noqa: E501 - :type letsencrypt: IngressConfigAllOfLetsencrypt :param auto: The auto of this IngressConfig. # noqa: E501 :type auto: bool :param name: The name of this IngressConfig. # noqa: E501 :type name: str + :param ssl_redirect: The ssl_redirect of this IngressConfig. # noqa: E501 + :type ssl_redirect: bool + :param letsencrypt: The letsencrypt of this IngressConfig. # noqa: E501 + :type letsencrypt: IngressConfigAllOfLetsencrypt """ self.openapi_types = { - 'ssl_redirect': bool, - 'letsencrypt': IngressConfigAllOfLetsencrypt, 'auto': bool, - 'name': str + 'name': str, + 'ssl_redirect': bool, + 'letsencrypt': IngressConfigAllOfLetsencrypt } self.attribute_map = { - 'ssl_redirect': 'ssl_redirect', - 'letsencrypt': 'letsencrypt', 'auto': 'auto', - 'name': 'name' + 'name': 'name', + 'ssl_redirect': 'ssl_redirect', + 'letsencrypt': 'letsencrypt' } - self._ssl_redirect = ssl_redirect - self._letsencrypt = letsencrypt self._auto = auto self._name = name + self._ssl_redirect = ssl_redirect + self._letsencrypt = letsencrypt @classmethod def from_dict(cls, dikt) -> 'IngressConfig': @@ -60,51 +57,7 @@ def from_dict(cls, dikt) -> 'IngressConfig': return util.deserialize_model(dikt, cls) @property - def ssl_redirect(self): - """Gets the ssl_redirect of this IngressConfig. - - # noqa: E501 - - :return: The ssl_redirect of this IngressConfig. - :rtype: bool - """ - return self._ssl_redirect - - @ssl_redirect.setter - def ssl_redirect(self, ssl_redirect): - """Sets the ssl_redirect of this IngressConfig. - - # noqa: E501 - - :param ssl_redirect: The ssl_redirect of this IngressConfig. - :type ssl_redirect: bool - """ - - self._ssl_redirect = ssl_redirect - - @property - def letsencrypt(self): - """Gets the letsencrypt of this IngressConfig. - - - :return: The letsencrypt of this IngressConfig. - :rtype: IngressConfigAllOfLetsencrypt - """ - return self._letsencrypt - - @letsencrypt.setter - def letsencrypt(self, letsencrypt): - """Sets the letsencrypt of this IngressConfig. - - - :param letsencrypt: The letsencrypt of this IngressConfig. - :type letsencrypt: IngressConfigAllOfLetsencrypt - """ - - self._letsencrypt = letsencrypt - - @property - def auto(self): + def auto(self) -> bool: """Gets the auto of this IngressConfig. When true, enables automatic template # noqa: E501 @@ -115,7 +68,7 @@ def auto(self): return self._auto @auto.setter - def auto(self, auto): + def auto(self, auto: bool): """Sets the auto of this IngressConfig. When true, enables automatic template # noqa: E501 @@ -129,7 +82,7 @@ def auto(self, auto): self._auto = auto @property - def name(self): + def name(self) -> str: """Gets the name of this IngressConfig. # noqa: E501 @@ -140,7 +93,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this IngressConfig. # noqa: E501 @@ -150,3 +103,47 @@ def name(self, name): """ self._name = name + + @property + def ssl_redirect(self) -> bool: + """Gets the ssl_redirect of this IngressConfig. + + # noqa: E501 + + :return: The ssl_redirect of this IngressConfig. + :rtype: bool + """ + return self._ssl_redirect + + @ssl_redirect.setter + def ssl_redirect(self, ssl_redirect: bool): + """Sets the ssl_redirect of this IngressConfig. + + # noqa: E501 + + :param ssl_redirect: The ssl_redirect of this IngressConfig. + :type ssl_redirect: bool + """ + + self._ssl_redirect = ssl_redirect + + @property + def letsencrypt(self) -> IngressConfigAllOfLetsencrypt: + """Gets the letsencrypt of this IngressConfig. + + + :return: The letsencrypt of this IngressConfig. + :rtype: IngressConfigAllOfLetsencrypt + """ + return self._letsencrypt + + @letsencrypt.setter + def letsencrypt(self, letsencrypt: IngressConfigAllOfLetsencrypt): + """Sets the letsencrypt of this IngressConfig. + + + :param letsencrypt: The letsencrypt of this IngressConfig. + :type letsencrypt: IngressConfigAllOfLetsencrypt + """ + + self._letsencrypt = letsencrypt diff --git a/libraries/models/cloudharness_model/models/ingress_config_all_of_letsencrypt.py b/libraries/models/cloudharness_model/models/ingress_config_all_of_letsencrypt.py index 0e8a5ab82..467e18a2d 100644 --- a/libraries/models/cloudharness_model/models/ingress_config_all_of_letsencrypt.py +++ b/libraries/models/cloudharness_model/models/ingress_config_all_of_letsencrypt.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -43,7 +40,7 @@ def from_dict(cls, dikt) -> 'IngressConfigAllOfLetsencrypt': return util.deserialize_model(dikt, cls) @property - def email(self): + def email(self) -> str: """Gets the email of this IngressConfigAllOfLetsencrypt. @@ -53,7 +50,7 @@ def email(self): return self._email @email.setter - def email(self, email): + def email(self, email: str): """Sets the email of this IngressConfigAllOfLetsencrypt. diff --git a/libraries/models/cloudharness_model/models/jupyter_hub_config.py b/libraries/models/cloudharness_model/models/jupyter_hub_config.py index 1f04fa734..5aaa9850e 100644 --- a/libraries/models/cloudharness_model/models/jupyter_hub_config.py +++ b/libraries/models/cloudharness_model/models/jupyter_hub_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -58,7 +55,7 @@ def from_dict(cls, dikt) -> 'JupyterHubConfig': return util.deserialize_model(dikt, cls) @property - def args(self): + def args(self) -> List[str]: """Gets the args of this JupyterHubConfig. arguments passed to the container # noqa: E501 @@ -69,7 +66,7 @@ def args(self): return self._args @args.setter - def args(self, args): + def args(self, args: List[str]): """Sets the args of this JupyterHubConfig. arguments passed to the container # noqa: E501 @@ -81,7 +78,7 @@ def args(self, args): self._args = args @property - def extra_config(self): + def extra_config(self) -> Dict[str, object]: """Gets the extra_config of this JupyterHubConfig. # noqa: E501 @@ -92,7 +89,7 @@ def extra_config(self): return self._extra_config @extra_config.setter - def extra_config(self, extra_config): + def extra_config(self, extra_config: Dict[str, object]): """Sets the extra_config of this JupyterHubConfig. # noqa: E501 @@ -104,7 +101,7 @@ def extra_config(self, extra_config): self._extra_config = extra_config @property - def spawner_extra_config(self): + def spawner_extra_config(self) -> Dict[str, object]: """Gets the spawner_extra_config of this JupyterHubConfig. # noqa: E501 @@ -115,7 +112,7 @@ def spawner_extra_config(self): return self._spawner_extra_config @spawner_extra_config.setter - def spawner_extra_config(self, spawner_extra_config): + def spawner_extra_config(self, spawner_extra_config: Dict[str, object]): """Sets the spawner_extra_config of this JupyterHubConfig. # noqa: E501 @@ -127,7 +124,7 @@ def spawner_extra_config(self, spawner_extra_config): self._spawner_extra_config = spawner_extra_config @property - def application_hook(self): + def application_hook(self) -> object: """Gets the application_hook of this JupyterHubConfig. change the hook function (advanced) Specify the Python name of the function (full module path, the module must be installed in the Docker image) # noqa: E501 @@ -138,7 +135,7 @@ def application_hook(self): return self._application_hook @application_hook.setter - def application_hook(self, application_hook): + def application_hook(self, application_hook: object): """Sets the application_hook of this JupyterHubConfig. change the hook function (advanced) Specify the Python name of the function (full module path, the module must be installed in the Docker image) # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/name_value.py b/libraries/models/cloudharness_model/models/name_value.py index f4b75cdd5..abf07fe68 100644 --- a/libraries/models/cloudharness_model/models/name_value.py +++ b/libraries/models/cloudharness_model/models/name_value.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -48,7 +45,7 @@ def from_dict(cls, dikt) -> 'NameValue': return util.deserialize_model(dikt, cls) @property - def name(self): + def name(self) -> str: """Gets the name of this NameValue. # noqa: E501 @@ -59,7 +56,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this NameValue. # noqa: E501 @@ -73,7 +70,7 @@ def name(self, name): self._name = name @property - def value(self): + def value(self) -> str: """Gets the value of this NameValue. # noqa: E501 @@ -84,7 +81,7 @@ def value(self): return self._value @value.setter - def value(self, value): + def value(self, value: str): """Sets the value of this NameValue. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/registry_config.py b/libraries/models/cloudharness_model/models/registry_config.py index 79f270279..7ce48e9cb 100644 --- a/libraries/models/cloudharness_model/models/registry_config.py +++ b/libraries/models/cloudharness_model/models/registry_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -48,7 +45,7 @@ def from_dict(cls, dikt) -> 'RegistryConfig': return util.deserialize_model(dikt, cls) @property - def name(self): + def name(self) -> str: """Gets the name of this RegistryConfig. # noqa: E501 @@ -59,7 +56,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this RegistryConfig. # noqa: E501 @@ -73,7 +70,7 @@ def name(self, name): self._name = name @property - def secret(self): + def secret(self) -> str: """Gets the secret of this RegistryConfig. Optional secret used for pulling from docker registry. # noqa: E501 @@ -84,7 +81,7 @@ def secret(self): return self._secret @secret.setter - def secret(self, secret): + def secret(self, secret: str): """Sets the secret of this RegistryConfig. Optional secret used for pulling from docker registry. # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/service_auto_artifact_config.py b/libraries/models/cloudharness_model/models/service_auto_artifact_config.py index 8d14ac42e..77bded861 100644 --- a/libraries/models/cloudharness_model/models/service_auto_artifact_config.py +++ b/libraries/models/cloudharness_model/models/service_auto_artifact_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -15,31 +12,31 @@ class ServiceAutoArtifactConfig(Model): Do not edit the class manually. """ - def __init__(self, port=None, auto=None, name=None): # noqa: E501 + def __init__(self, auto=None, name=None, port=None): # noqa: E501 """ServiceAutoArtifactConfig - a model defined in OpenAPI - :param port: The port of this ServiceAutoArtifactConfig. # noqa: E501 - :type port: int :param auto: The auto of this ServiceAutoArtifactConfig. # noqa: E501 :type auto: bool :param name: The name of this ServiceAutoArtifactConfig. # noqa: E501 :type name: str + :param port: The port of this ServiceAutoArtifactConfig. # noqa: E501 + :type port: int """ self.openapi_types = { - 'port': int, 'auto': bool, - 'name': str + 'name': str, + 'port': int } self.attribute_map = { - 'port': 'port', 'auto': 'auto', - 'name': 'name' + 'name': 'name', + 'port': 'port' } - self._port = port self._auto = auto self._name = name + self._port = port @classmethod def from_dict(cls, dikt) -> 'ServiceAutoArtifactConfig': @@ -53,30 +50,7 @@ def from_dict(cls, dikt) -> 'ServiceAutoArtifactConfig': return util.deserialize_model(dikt, cls) @property - def port(self): - """Gets the port of this ServiceAutoArtifactConfig. - - Service port # noqa: E501 - - :return: The port of this ServiceAutoArtifactConfig. - :rtype: int - """ - return self._port - - @port.setter - def port(self, port): - """Sets the port of this ServiceAutoArtifactConfig. - - Service port # noqa: E501 - - :param port: The port of this ServiceAutoArtifactConfig. - :type port: int - """ - - self._port = port - - @property - def auto(self): + def auto(self) -> bool: """Gets the auto of this ServiceAutoArtifactConfig. When true, enables automatic template # noqa: E501 @@ -87,7 +61,7 @@ def auto(self): return self._auto @auto.setter - def auto(self, auto): + def auto(self, auto: bool): """Sets the auto of this ServiceAutoArtifactConfig. When true, enables automatic template # noqa: E501 @@ -101,7 +75,7 @@ def auto(self, auto): self._auto = auto @property - def name(self): + def name(self) -> str: """Gets the name of this ServiceAutoArtifactConfig. # noqa: E501 @@ -112,7 +86,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this ServiceAutoArtifactConfig. # noqa: E501 @@ -122,3 +96,26 @@ def name(self, name): """ self._name = name + + @property + def port(self) -> int: + """Gets the port of this ServiceAutoArtifactConfig. + + Service port # noqa: E501 + + :return: The port of this ServiceAutoArtifactConfig. + :rtype: int + """ + return self._port + + @port.setter + def port(self, port: int): + """Sets the port of this ServiceAutoArtifactConfig. + + Service port # noqa: E501 + + :param port: The port of this ServiceAutoArtifactConfig. + :type port: int + """ + + self._port = port diff --git a/libraries/models/cloudharness_model/models/unit_tests_config.py b/libraries/models/cloudharness_model/models/unit_tests_config.py index 9b7813c84..680d984a5 100644 --- a/libraries/models/cloudharness_model/models/unit_tests_config.py +++ b/libraries/models/cloudharness_model/models/unit_tests_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -48,7 +45,7 @@ def from_dict(cls, dikt) -> 'UnitTestsConfig': return util.deserialize_model(dikt, cls) @property - def enabled(self): + def enabled(self) -> bool: """Gets the enabled of this UnitTestsConfig. Enables unit tests for this application (default: true) # noqa: E501 @@ -59,7 +56,7 @@ def enabled(self): return self._enabled @enabled.setter - def enabled(self, enabled): + def enabled(self, enabled: bool): """Sets the enabled of this UnitTestsConfig. Enables unit tests for this application (default: true) # noqa: E501 @@ -73,7 +70,7 @@ def enabled(self, enabled): self._enabled = enabled @property - def commands(self): + def commands(self) -> List[str]: """Gets the commands of this UnitTestsConfig. Commands to run unit tests # noqa: E501 @@ -84,7 +81,7 @@ def commands(self): return self._commands @commands.setter - def commands(self, commands): + def commands(self, commands: List[str]): """Sets the commands of this UnitTestsConfig. Commands to run unit tests # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/uri_role_mapping_config.py b/libraries/models/cloudharness_model/models/uri_role_mapping_config.py index 046beccaa..649ae22e4 100644 --- a/libraries/models/cloudharness_model/models/uri_role_mapping_config.py +++ b/libraries/models/cloudharness_model/models/uri_role_mapping_config.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model import re from cloudharness_model import util @@ -50,7 +47,7 @@ def from_dict(cls, dikt) -> 'UriRoleMappingConfig': return util.deserialize_model(dikt, cls) @property - def uri(self): + def uri(self) -> str: """Gets the uri of this UriRoleMappingConfig. # noqa: E501 @@ -61,7 +58,7 @@ def uri(self): return self._uri @uri.setter - def uri(self, uri): + def uri(self, uri: str): """Sets the uri of this UriRoleMappingConfig. # noqa: E501 @@ -77,7 +74,7 @@ def uri(self, uri): self._uri = uri @property - def roles(self): + def roles(self) -> List[str]: """Gets the roles of this UriRoleMappingConfig. Roles allowed to access the present uri # noqa: E501 @@ -88,7 +85,7 @@ def roles(self): return self._roles @roles.setter - def roles(self, roles): + def roles(self, roles: List[str]): """Sets the roles of this UriRoleMappingConfig. Roles allowed to access the present uri # noqa: E501 diff --git a/libraries/models/cloudharness_model/models/user.py b/libraries/models/cloudharness_model/models/user.py index 3d1c18955..0676fbae8 100644 --- a/libraries/models/cloudharness_model/models/user.py +++ b/libraries/models/cloudharness_model/models/user.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model.models.user_credential import UserCredential from cloudharness_model import util @@ -135,7 +132,7 @@ def from_dict(cls, dikt) -> 'User': return util.deserialize_model(dikt, cls) @property - def access(self): + def access(self) -> Dict[str, object]: """Gets the access of this User. @@ -145,7 +142,7 @@ def access(self): return self._access @access.setter - def access(self, access): + def access(self, access: Dict[str, object]): """Sets the access of this User. @@ -156,7 +153,7 @@ def access(self, access): self._access = access @property - def attributes(self): + def attributes(self) -> Dict[str, object]: """Gets the attributes of this User. @@ -166,7 +163,7 @@ def attributes(self): return self._attributes @attributes.setter - def attributes(self, attributes): + def attributes(self, attributes: Dict[str, object]): """Sets the attributes of this User. @@ -177,7 +174,7 @@ def attributes(self, attributes): self._attributes = attributes @property - def client_roles(self): + def client_roles(self) -> Dict[str, object]: """Gets the client_roles of this User. @@ -187,7 +184,7 @@ def client_roles(self): return self._client_roles @client_roles.setter - def client_roles(self, client_roles): + def client_roles(self, client_roles: Dict[str, object]): """Sets the client_roles of this User. @@ -198,7 +195,7 @@ def client_roles(self, client_roles): self._client_roles = client_roles @property - def created_timestamp(self): + def created_timestamp(self) -> int: """Gets the created_timestamp of this User. @@ -208,7 +205,7 @@ def created_timestamp(self): return self._created_timestamp @created_timestamp.setter - def created_timestamp(self, created_timestamp): + def created_timestamp(self, created_timestamp: int): """Sets the created_timestamp of this User. @@ -219,7 +216,7 @@ def created_timestamp(self, created_timestamp): self._created_timestamp = created_timestamp @property - def credentials(self): + def credentials(self) -> List[UserCredential]: """Gets the credentials of this User. @@ -229,7 +226,7 @@ def credentials(self): return self._credentials @credentials.setter - def credentials(self, credentials): + def credentials(self, credentials: List[UserCredential]): """Sets the credentials of this User. @@ -240,7 +237,7 @@ def credentials(self, credentials): self._credentials = credentials @property - def disableable_credential_types(self): + def disableable_credential_types(self) -> List[str]: """Gets the disableable_credential_types of this User. @@ -250,7 +247,7 @@ def disableable_credential_types(self): return self._disableable_credential_types @disableable_credential_types.setter - def disableable_credential_types(self, disableable_credential_types): + def disableable_credential_types(self, disableable_credential_types: List[str]): """Sets the disableable_credential_types of this User. @@ -261,7 +258,7 @@ def disableable_credential_types(self, disableable_credential_types): self._disableable_credential_types = disableable_credential_types @property - def email(self): + def email(self) -> str: """Gets the email of this User. @@ -271,7 +268,7 @@ def email(self): return self._email @email.setter - def email(self, email): + def email(self, email: str): """Sets the email of this User. @@ -282,7 +279,7 @@ def email(self, email): self._email = email @property - def email_verified(self): + def email_verified(self) -> bool: """Gets the email_verified of this User. @@ -292,7 +289,7 @@ def email_verified(self): return self._email_verified @email_verified.setter - def email_verified(self, email_verified): + def email_verified(self, email_verified: bool): """Sets the email_verified of this User. @@ -303,7 +300,7 @@ def email_verified(self, email_verified): self._email_verified = email_verified @property - def enabled(self): + def enabled(self) -> bool: """Gets the enabled of this User. @@ -313,7 +310,7 @@ def enabled(self): return self._enabled @enabled.setter - def enabled(self, enabled): + def enabled(self, enabled: bool): """Sets the enabled of this User. @@ -324,7 +321,7 @@ def enabled(self, enabled): self._enabled = enabled @property - def federation_link(self): + def federation_link(self) -> str: """Gets the federation_link of this User. @@ -334,7 +331,7 @@ def federation_link(self): return self._federation_link @federation_link.setter - def federation_link(self, federation_link): + def federation_link(self, federation_link: str): """Sets the federation_link of this User. @@ -345,7 +342,7 @@ def federation_link(self, federation_link): self._federation_link = federation_link @property - def first_name(self): + def first_name(self) -> str: """Gets the first_name of this User. @@ -355,7 +352,7 @@ def first_name(self): return self._first_name @first_name.setter - def first_name(self, first_name): + def first_name(self, first_name: str): """Sets the first_name of this User. @@ -366,7 +363,7 @@ def first_name(self, first_name): self._first_name = first_name @property - def groups(self): + def groups(self) -> List[str]: """Gets the groups of this User. @@ -376,7 +373,7 @@ def groups(self): return self._groups @groups.setter - def groups(self, groups): + def groups(self, groups: List[str]): """Sets the groups of this User. @@ -387,7 +384,7 @@ def groups(self, groups): self._groups = groups @property - def id(self): + def id(self) -> str: """Gets the id of this User. @@ -397,7 +394,7 @@ def id(self): return self._id @id.setter - def id(self, id): + def id(self, id: str): """Sets the id of this User. @@ -408,7 +405,7 @@ def id(self, id): self._id = id @property - def last_name(self): + def last_name(self) -> str: """Gets the last_name of this User. @@ -418,7 +415,7 @@ def last_name(self): return self._last_name @last_name.setter - def last_name(self, last_name): + def last_name(self, last_name: str): """Sets the last_name of this User. @@ -429,7 +426,7 @@ def last_name(self, last_name): self._last_name = last_name @property - def realm_roles(self): + def realm_roles(self) -> List[str]: """Gets the realm_roles of this User. @@ -439,7 +436,7 @@ def realm_roles(self): return self._realm_roles @realm_roles.setter - def realm_roles(self, realm_roles): + def realm_roles(self, realm_roles: List[str]): """Sets the realm_roles of this User. @@ -450,7 +447,7 @@ def realm_roles(self, realm_roles): self._realm_roles = realm_roles @property - def required_actions(self): + def required_actions(self) -> List[str]: """Gets the required_actions of this User. @@ -460,7 +457,7 @@ def required_actions(self): return self._required_actions @required_actions.setter - def required_actions(self, required_actions): + def required_actions(self, required_actions: List[str]): """Sets the required_actions of this User. @@ -471,7 +468,7 @@ def required_actions(self, required_actions): self._required_actions = required_actions @property - def service_account_client_id(self): + def service_account_client_id(self) -> str: """Gets the service_account_client_id of this User. @@ -481,7 +478,7 @@ def service_account_client_id(self): return self._service_account_client_id @service_account_client_id.setter - def service_account_client_id(self, service_account_client_id): + def service_account_client_id(self, service_account_client_id: str): """Sets the service_account_client_id of this User. @@ -492,7 +489,7 @@ def service_account_client_id(self, service_account_client_id): self._service_account_client_id = service_account_client_id @property - def username(self): + def username(self) -> str: """Gets the username of this User. @@ -502,7 +499,7 @@ def username(self): return self._username @username.setter - def username(self, username): + def username(self, username: str): """Sets the username of this User. @@ -513,7 +510,7 @@ def username(self, username): self._username = username @property - def additional_properties(self): + def additional_properties(self) -> object: """Gets the additional_properties of this User. @@ -523,7 +520,7 @@ def additional_properties(self): return self._additional_properties @additional_properties.setter - def additional_properties(self, additional_properties): + def additional_properties(self, additional_properties: object): """Sets the additional_properties of this User. diff --git a/libraries/models/cloudharness_model/models/user_credential.py b/libraries/models/cloudharness_model/models/user_credential.py index 4f54ddf50..1b692f8f9 100644 --- a/libraries/models/cloudharness_model/models/user_credential.py +++ b/libraries/models/cloudharness_model/models/user_credential.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -83,7 +80,7 @@ def from_dict(cls, dikt) -> 'UserCredential': return util.deserialize_model(dikt, cls) @property - def created_date(self): + def created_date(self) -> int: """Gets the created_date of this UserCredential. @@ -93,7 +90,7 @@ def created_date(self): return self._created_date @created_date.setter - def created_date(self, created_date): + def created_date(self, created_date: int): """Sets the created_date of this UserCredential. @@ -104,7 +101,7 @@ def created_date(self, created_date): self._created_date = created_date @property - def credential_data(self): + def credential_data(self) -> str: """Gets the credential_data of this UserCredential. @@ -114,7 +111,7 @@ def credential_data(self): return self._credential_data @credential_data.setter - def credential_data(self, credential_data): + def credential_data(self, credential_data: str): """Sets the credential_data of this UserCredential. @@ -125,7 +122,7 @@ def credential_data(self, credential_data): self._credential_data = credential_data @property - def id(self): + def id(self) -> str: """Gets the id of this UserCredential. @@ -135,7 +132,7 @@ def id(self): return self._id @id.setter - def id(self, id): + def id(self, id: str): """Sets the id of this UserCredential. @@ -146,7 +143,7 @@ def id(self, id): self._id = id @property - def priority(self): + def priority(self) -> int: """Gets the priority of this UserCredential. @@ -156,7 +153,7 @@ def priority(self): return self._priority @priority.setter - def priority(self, priority): + def priority(self, priority: int): """Sets the priority of this UserCredential. @@ -167,7 +164,7 @@ def priority(self, priority): self._priority = priority @property - def secret_data(self): + def secret_data(self) -> str: """Gets the secret_data of this UserCredential. @@ -177,7 +174,7 @@ def secret_data(self): return self._secret_data @secret_data.setter - def secret_data(self, secret_data): + def secret_data(self, secret_data: str): """Sets the secret_data of this UserCredential. @@ -188,7 +185,7 @@ def secret_data(self, secret_data): self._secret_data = secret_data @property - def temporary(self): + def temporary(self) -> bool: """Gets the temporary of this UserCredential. @@ -198,7 +195,7 @@ def temporary(self): return self._temporary @temporary.setter - def temporary(self, temporary): + def temporary(self, temporary: bool): """Sets the temporary of this UserCredential. @@ -209,7 +206,7 @@ def temporary(self, temporary): self._temporary = temporary @property - def type(self): + def type(self) -> str: """Gets the type of this UserCredential. @@ -219,7 +216,7 @@ def type(self): return self._type @type.setter - def type(self, type): + def type(self, type: str): """Sets the type of this UserCredential. @@ -230,7 +227,7 @@ def type(self, type): self._type = type @property - def user_label(self): + def user_label(self) -> str: """Gets the user_label of this UserCredential. @@ -240,7 +237,7 @@ def user_label(self): return self._user_label @user_label.setter - def user_label(self, user_label): + def user_label(self, user_label: str): """Sets the user_label of this UserCredential. @@ -251,7 +248,7 @@ def user_label(self, user_label): self._user_label = user_label @property - def value(self): + def value(self) -> str: """Gets the value of this UserCredential. @@ -261,7 +258,7 @@ def value(self): return self._value @value.setter - def value(self, value): + def value(self, value: str): """Sets the value of this UserCredential. diff --git a/libraries/models/cloudharness_model/models/user_group.py b/libraries/models/cloudharness_model/models/user_group.py index 72e135efb..0cf48e994 100644 --- a/libraries/models/cloudharness_model/models/user_group.py +++ b/libraries/models/cloudharness_model/models/user_group.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -78,7 +75,7 @@ def from_dict(cls, dikt) -> 'UserGroup': return util.deserialize_model(dikt, cls) @property - def access(self): + def access(self) -> Dict[str, object]: """Gets the access of this UserGroup. @@ -88,7 +85,7 @@ def access(self): return self._access @access.setter - def access(self, access): + def access(self, access: Dict[str, object]): """Sets the access of this UserGroup. @@ -99,7 +96,7 @@ def access(self, access): self._access = access @property - def attributes(self): + def attributes(self) -> Dict[str, object]: """Gets the attributes of this UserGroup. # noqa: E501 @@ -110,7 +107,7 @@ def attributes(self): return self._attributes @attributes.setter - def attributes(self, attributes): + def attributes(self, attributes: Dict[str, object]): """Sets the attributes of this UserGroup. # noqa: E501 @@ -122,7 +119,7 @@ def attributes(self, attributes): self._attributes = attributes @property - def client_roles(self): + def client_roles(self) -> Dict[str, object]: """Gets the client_roles of this UserGroup. @@ -132,7 +129,7 @@ def client_roles(self): return self._client_roles @client_roles.setter - def client_roles(self, client_roles): + def client_roles(self, client_roles: Dict[str, object]): """Sets the client_roles of this UserGroup. @@ -143,7 +140,7 @@ def client_roles(self, client_roles): self._client_roles = client_roles @property - def id(self): + def id(self) -> str: """Gets the id of this UserGroup. @@ -153,7 +150,7 @@ def id(self): return self._id @id.setter - def id(self, id): + def id(self, id: str): """Sets the id of this UserGroup. @@ -164,7 +161,7 @@ def id(self, id): self._id = id @property - def name(self): + def name(self) -> str: """Gets the name of this UserGroup. @@ -174,7 +171,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this UserGroup. @@ -185,7 +182,7 @@ def name(self, name): self._name = name @property - def path(self): + def path(self) -> str: """Gets the path of this UserGroup. @@ -195,7 +192,7 @@ def path(self): return self._path @path.setter - def path(self, path): + def path(self, path: str): """Sets the path of this UserGroup. @@ -206,7 +203,7 @@ def path(self, path): self._path = path @property - def realm_roles(self): + def realm_roles(self) -> List[str]: """Gets the realm_roles of this UserGroup. @@ -216,7 +213,7 @@ def realm_roles(self): return self._realm_roles @realm_roles.setter - def realm_roles(self, realm_roles): + def realm_roles(self, realm_roles: List[str]): """Sets the realm_roles of this UserGroup. @@ -227,7 +224,7 @@ def realm_roles(self, realm_roles): self._realm_roles = realm_roles @property - def sub_groups(self): + def sub_groups(self) -> List[UserGroup]: """Gets the sub_groups of this UserGroup. @@ -237,7 +234,7 @@ def sub_groups(self): return self._sub_groups @sub_groups.setter - def sub_groups(self, sub_groups): + def sub_groups(self, sub_groups: List[UserGroup]): """Sets the sub_groups of this UserGroup. diff --git a/libraries/models/cloudharness_model/models/user_role.py b/libraries/models/cloudharness_model/models/user_role.py index dfa7e529b..8cbc7d005 100644 --- a/libraries/models/cloudharness_model/models/user_role.py +++ b/libraries/models/cloudharness_model/models/user_role.py @@ -1,11 +1,8 @@ -# coding: utf-8 - -from __future__ import absolute_import from datetime import date, datetime # noqa: F401 from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model_ import Model +from cloudharness_model.models.base_model import Model from cloudharness_model import util @@ -73,7 +70,7 @@ def from_dict(cls, dikt) -> 'UserRole': return util.deserialize_model(dikt, cls) @property - def attributes(self): + def attributes(self) -> Dict[str, object]: """Gets the attributes of this UserRole. @@ -83,7 +80,7 @@ def attributes(self): return self._attributes @attributes.setter - def attributes(self, attributes): + def attributes(self, attributes: Dict[str, object]): """Sets the attributes of this UserRole. @@ -94,7 +91,7 @@ def attributes(self, attributes): self._attributes = attributes @property - def client_role(self): + def client_role(self) -> bool: """Gets the client_role of this UserRole. @@ -104,7 +101,7 @@ def client_role(self): return self._client_role @client_role.setter - def client_role(self, client_role): + def client_role(self, client_role: bool): """Sets the client_role of this UserRole. @@ -115,7 +112,7 @@ def client_role(self, client_role): self._client_role = client_role @property - def composite(self): + def composite(self) -> bool: """Gets the composite of this UserRole. @@ -125,7 +122,7 @@ def composite(self): return self._composite @composite.setter - def composite(self, composite): + def composite(self, composite: bool): """Sets the composite of this UserRole. @@ -136,7 +133,7 @@ def composite(self, composite): self._composite = composite @property - def container_id(self): + def container_id(self) -> str: """Gets the container_id of this UserRole. @@ -146,7 +143,7 @@ def container_id(self): return self._container_id @container_id.setter - def container_id(self, container_id): + def container_id(self, container_id: str): """Sets the container_id of this UserRole. @@ -157,7 +154,7 @@ def container_id(self, container_id): self._container_id = container_id @property - def description(self): + def description(self) -> str: """Gets the description of this UserRole. @@ -167,7 +164,7 @@ def description(self): return self._description @description.setter - def description(self, description): + def description(self, description: str): """Sets the description of this UserRole. @@ -178,7 +175,7 @@ def description(self, description): self._description = description @property - def id(self): + def id(self) -> str: """Gets the id of this UserRole. @@ -188,7 +185,7 @@ def id(self): return self._id @id.setter - def id(self, id): + def id(self, id: str): """Sets the id of this UserRole. @@ -199,7 +196,7 @@ def id(self, id): self._id = id @property - def name(self): + def name(self) -> str: """Gets the name of this UserRole. @@ -209,7 +206,7 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): """Sets the name of this UserRole. diff --git a/libraries/models/cloudharness_model/typing_utils.py b/libraries/models/cloudharness_model/typing_utils.py index 0563f81fd..74e3c913a 100644 --- a/libraries/models/cloudharness_model/typing_utils.py +++ b/libraries/models/cloudharness_model/typing_utils.py @@ -1,5 +1,3 @@ -# coding: utf-8 - import sys if sys.version_info < (3, 7): diff --git a/libraries/models/tox.ini b/libraries/models/tox.ini index e76b6dbf5..132efa3e2 100644 --- a/libraries/models/tox.ini +++ b/libraries/models/tox.ini @@ -5,7 +5,7 @@ skipsdist=True [testenv] deps=-r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt - {toxinidir} + {toxinidir} commands= pytest --cov=cloudharness_model From 831bd1c5644d1aa88af48c6a4195f810da952244 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 29 Jul 2024 16:06:29 +0100 Subject: [PATCH 11/37] CH-91 Updated the auto deployment template to include the envmap and added an example to samples --- .../samples/controllers/test_controller.py | 16 ++++++++++++++++ applications/samples/deploy/values.yaml | 3 +++ .../helm/templates/auto-deployments.yaml | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/applications/samples/backend/samples/controllers/test_controller.py b/applications/samples/backend/samples/controllers/test_controller.py index e792c99e0..3fb922f24 100644 --- a/applications/samples/backend/samples/controllers/test_controller.py +++ b/applications/samples/backend/samples/controllers/test_controller.py @@ -22,6 +22,22 @@ def ping(): # noqa: E501 :rtype: str """ + + import os + + expected_environment_variables = { + 'ENVIRONMENT_TEST_A': 'value', + 'ENVIRONMENT_TEST_B': '123', + } + + for key, expected_value in expected_environment_variables.items(): + try: + environment_value = os.environ[key] + if environment_value != expected_value: + raise Exception(f'Expected environment variable {key} to be {expected_value}, but got {environment_value}') + except KeyError: + raise Exception(f'Expected to have an environment variable {key} defined') + import time return time.time() diff --git a/applications/samples/deploy/values.yaml b/applications/samples/deploy/values.yaml index 6265c6811..ab22f1e5e 100644 --- a/applications/samples/deploy/values.yaml +++ b/applications/samples/deploy/values.yaml @@ -39,6 +39,9 @@ harness: env: - name: WORKERS value: "3" + envmap: + ENVIRONMENT_TEST_A: "value" + ENVIRONMENT_TEST_B: 123 dependencies: soft: - workflows diff --git a/deployment-configuration/helm/templates/auto-deployments.yaml b/deployment-configuration/helm/templates/auto-deployments.yaml index 23d4f61cd..6981c2fd4 100644 --- a/deployment-configuration/helm/templates/auto-deployments.yaml +++ b/deployment-configuration/helm/templates/auto-deployments.yaml @@ -66,6 +66,10 @@ spec: {{- if .app.harness.env }} {{- .app.harness.env | toYaml | nindent 8 }} {{- end }} + {{- range $name, $value := .app.harness.envmap }} + - name: {{ $name | quote }} + value: {{ $value | quote }} + {{- end }} {{ if .app.harness.livenessProbe }} livenessProbe: httpGet: From 9d7a648789908d6c2c5484b204e06f6df3c3c640 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 29 Jul 2024 16:56:01 +0100 Subject: [PATCH 12/37] CH-91 Updated documentation around environment variables --- docs/applications/README.md | 5 ++- docs/applications/environment-variables.md | 46 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 docs/applications/environment-variables.md diff --git a/docs/applications/README.md b/docs/applications/README.md index e76bd861c..da0c44fa1 100644 --- a/docs/applications/README.md +++ b/docs/applications/README.md @@ -109,7 +109,10 @@ The most important configuration entries are the following: - `postgres`: postgres specific configurations - `mongo`: mongo specific configurations - `neo4j`: neo4j specific configurations - - `env` (`{name, value}[]`): add custom environment variables + - `envmap`: add custom environment variables + - ``: `` + - ... + - `env` (`{name, value}[]`): add custom environment variables (deprecated, please use `envmap`) - `resources`: mount files from - `use_services` (`{name, src, dst}[]`): create reverse proxy endpoints in the ingress for the listed applications on [subdomain].[Values.domain]/proxy/[name]. Useful to avoid CORS requests from frontend clients - `readinessProbe`: defines a a url to use as a readiness probe diff --git a/docs/applications/environment-variables.md b/docs/applications/environment-variables.md new file mode 100644 index 000000000..f986ec388 --- /dev/null +++ b/docs/applications/environment-variables.md @@ -0,0 +1,46 @@ +# CloudHarness Environment Variables + +CloudHarness has support for adding environment variables for an application which will be available to all containers within the application pod. + +## Automatically included environment variables + +The following environment variables are included in each container by default: +- `CH_CURRENT_APP_NAME`: the name of the application +- Any environment variables defined in the root `.Values.env` +- If `accounts` is an included application: + - `CH_ACCOUNTS_CLIENT_SECRET`: the client secret for the accounts + - `CH_ACCOUNTS_REALM`: the accounts realm + - `CH_ACCOUNTS_AUTH_DOMAIN`: the auth domain for the accounts + - `CH_ACCOUNTS_CLIENT_ID`: the client id for the accounts + - `DOMAIN`: the domain for the accounts + +## Environment variables definition in CloudHarness + +Environment variables are defined in the application values.yaml file in the `envmap` section under the `harness` section. +Example + +```yaml +harness: + envmap: + ENV_VARIABLE_A: + ... +``` + +Each key in the `envmap` will add an environment variable with a name matching the key and a value equal to the value provided. The value can be any primitive type, but will be quoted as a string within the deployment template. + +### (Deprecated) Setting with `env` + +Environment variables can be defined by using the `env` section under the `harness` section. This functionality is deprecated but not yet obsoleted, and use of `envmap` should be preferred over this approach. +Example + +```yaml +harness: + env: + - name: ENV_VARIABLE_A + value: + ... +``` + +Each element of the `env` sequence will add an environment variable named `name` with value set from `value`. + +This functionality was deprecated as cloud harness cannot merge arrays, so if an environment variable needed changing in a specific environment the entire array must be reproduced to change the single variable. \ No newline at end of file From 3a0e4f14f8d5cda23819a1cc3ffb5323752ad278 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Tue, 30 Jul 2024 10:32:25 +0100 Subject: [PATCH 13/37] CH-91 Updated model documentation generation to use the directory docs are actually generated to --- docs/model/ApiTestsConfig.md | 33 ++++++++++++ docs/model/ApplicationAccountsConfig.md | 31 ++++++++++++ docs/model/ApplicationConfig.md | 30 +++++++++++ docs/model/ApplicationDependenciesConfig.md | 33 ++++++++++++ docs/model/ApplicationHarnessConfig.md | 50 +++++++++++++++++++ docs/model/ApplicationProbe.md | 33 ++++++++++++ docs/model/ApplicationTestConfig.md | 32 ++++++++++++ docs/model/ApplicationUser.md | 33 ++++++++++++ docs/model/AutoArtifactSpec.md | 31 ++++++++++++ docs/model/BackupConfig.md | 38 ++++++++++++++ docs/model/CDCEvent.md | 34 +++++++++++++ docs/model/CDCEventMeta.md | 34 +++++++++++++ docs/model/CpuMemoryConfig.md | 31 ++++++++++++ docs/model/DatabaseDeploymentConfig.md | 40 +++++++++++++++ docs/model/DeploymentAutoArtifactConfig.md | 36 +++++++++++++ docs/model/DeploymentResourcesConf.md | 31 ++++++++++++ docs/model/DeploymentVolumeSpec.md | 34 +++++++++++++ docs/model/E2ETestsConfig.md | 33 ++++++++++++ docs/model/FileResourcesConfig.md | 32 ++++++++++++ docs/model/GitDependencyConfig.md | 32 ++++++++++++ docs/model/HarnessMainConfig.md | 44 ++++++++++++++++ docs/model/IngressConfig.md | 33 ++++++++++++ docs/model/IngressConfigAllOfLetsencrypt.md | 30 +++++++++++ docs/model/JupyterHubConfig.md | 33 ++++++++++++ docs/model/NameValue.md | 31 ++++++++++++ docs/model/RegistryConfig.md | 31 ++++++++++++ docs/model/ServiceAutoArtifactConfig.md | 32 ++++++++++++ docs/model/UnitTestsConfig.md | 31 ++++++++++++ docs/model/UriRoleMappingConfig.md | 31 ++++++++++++ docs/model/User.md | 47 +++++++++++++++++ docs/model/UserCredential.md | 37 ++++++++++++++ docs/model/UserGroup.md | 36 +++++++++++++ docs/model/UserRole.md | 35 +++++++++++++ .../ch_cli_tools/openapi.py | 2 +- 34 files changed, 1133 insertions(+), 1 deletion(-) create mode 100644 docs/model/ApiTestsConfig.md create mode 100644 docs/model/ApplicationAccountsConfig.md create mode 100644 docs/model/ApplicationConfig.md create mode 100644 docs/model/ApplicationDependenciesConfig.md create mode 100644 docs/model/ApplicationHarnessConfig.md create mode 100644 docs/model/ApplicationProbe.md create mode 100644 docs/model/ApplicationTestConfig.md create mode 100644 docs/model/ApplicationUser.md create mode 100644 docs/model/AutoArtifactSpec.md create mode 100644 docs/model/BackupConfig.md create mode 100644 docs/model/CDCEvent.md create mode 100644 docs/model/CDCEventMeta.md create mode 100644 docs/model/CpuMemoryConfig.md create mode 100644 docs/model/DatabaseDeploymentConfig.md create mode 100644 docs/model/DeploymentAutoArtifactConfig.md create mode 100644 docs/model/DeploymentResourcesConf.md create mode 100644 docs/model/DeploymentVolumeSpec.md create mode 100644 docs/model/E2ETestsConfig.md create mode 100644 docs/model/FileResourcesConfig.md create mode 100644 docs/model/GitDependencyConfig.md create mode 100644 docs/model/HarnessMainConfig.md create mode 100644 docs/model/IngressConfig.md create mode 100644 docs/model/IngressConfigAllOfLetsencrypt.md create mode 100644 docs/model/JupyterHubConfig.md create mode 100644 docs/model/NameValue.md create mode 100644 docs/model/RegistryConfig.md create mode 100644 docs/model/ServiceAutoArtifactConfig.md create mode 100644 docs/model/UnitTestsConfig.md create mode 100644 docs/model/UriRoleMappingConfig.md create mode 100644 docs/model/User.md create mode 100644 docs/model/UserCredential.md create mode 100644 docs/model/UserGroup.md create mode 100644 docs/model/UserRole.md diff --git a/docs/model/ApiTestsConfig.md b/docs/model/ApiTestsConfig.md new file mode 100644 index 000000000..c0c0a347e --- /dev/null +++ b/docs/model/ApiTestsConfig.md @@ -0,0 +1,33 @@ +# ApiTestsConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**enabled** | **bool** | Enables api tests for this application (default: false) | +**autotest** | **bool** | Specify whether to run the common smoke tests | +**run_params** | **List[str]** | Additional schemathesis parameters | [optional] +**checks** | **List[str]** | One of the Schemathesis checks: - not_a_server_error. The response has 5xx HTTP status; - status_code_conformance. The response status is not defined in the API schema; - content_type_conformance. The response content type is not defined in the API schema; - response_schema_conformance. The response content does not conform to the schema defined for this specific response; - response_headers_conformance. The response headers does not contain all defined headers. | + +## Example + +```python +from cloudharness_model.models.api_tests_config import ApiTestsConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of ApiTestsConfig from a JSON string +api_tests_config_instance = ApiTestsConfig.from_json(json) +# print the JSON string representation of the object +print ApiTestsConfig.to_json() + +# convert the object into a dict +api_tests_config_dict = api_tests_config_instance.to_dict() +# create an instance of ApiTestsConfig from a dict +api_tests_config_form_dict = api_tests_config.from_dict(api_tests_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/ApplicationAccountsConfig.md b/docs/model/ApplicationAccountsConfig.md new file mode 100644 index 000000000..542dc891b --- /dev/null +++ b/docs/model/ApplicationAccountsConfig.md @@ -0,0 +1,31 @@ +# ApplicationAccountsConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**roles** | **List[str]** | Specify roles to be created in this deployment specific for this application | [optional] +**users** | [**List[ApplicationUser]**](ApplicationUser.md) | Defines test users to be added to the deployment, specific for this application | [optional] + +## Example + +```python +from cloudharness_model.models.application_accounts_config import ApplicationAccountsConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of ApplicationAccountsConfig from a JSON string +application_accounts_config_instance = ApplicationAccountsConfig.from_json(json) +# print the JSON string representation of the object +print ApplicationAccountsConfig.to_json() + +# convert the object into a dict +application_accounts_config_dict = application_accounts_config_instance.to_dict() +# create an instance of ApplicationAccountsConfig from a dict +application_accounts_config_form_dict = application_accounts_config.from_dict(application_accounts_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/ApplicationConfig.md b/docs/model/ApplicationConfig.md new file mode 100644 index 000000000..c62c5523c --- /dev/null +++ b/docs/model/ApplicationConfig.md @@ -0,0 +1,30 @@ +# ApplicationConfig + +Place here the values to configure your application helm templates. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**harness** | [**ApplicationHarnessConfig**](ApplicationHarnessConfig.md) | | + +## Example + +```python +from cloudharness_model.models.application_config import ApplicationConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of ApplicationConfig from a JSON string +application_config_instance = ApplicationConfig.from_json(json) +# print the JSON string representation of the object +print ApplicationConfig.to_json() + +# convert the object into a dict +application_config_dict = application_config_instance.to_dict() +# create an instance of ApplicationConfig from a dict +application_config_form_dict = application_config.from_dict(application_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/ApplicationDependenciesConfig.md b/docs/model/ApplicationDependenciesConfig.md new file mode 100644 index 000000000..1adfc23c5 --- /dev/null +++ b/docs/model/ApplicationDependenciesConfig.md @@ -0,0 +1,33 @@ +# ApplicationDependenciesConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**hard** | **List[str]** | Hard dependencies indicate that the application may not start without these other applications. | [optional] +**soft** | **List[str]** | Soft dependencies indicate that the application will work partially without these other applications. | [optional] +**build** | **List[str]** | Hard dependencies indicate that the application Docker image build requires these base/common images | [optional] +**git** | [**List[GitDependencyConfig]**](GitDependencyConfig.md) | | [optional] + +## Example + +```python +from cloudharness_model.models.application_dependencies_config import ApplicationDependenciesConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of ApplicationDependenciesConfig from a JSON string +application_dependencies_config_instance = ApplicationDependenciesConfig.from_json(json) +# print the JSON string representation of the object +print ApplicationDependenciesConfig.to_json() + +# convert the object into a dict +application_dependencies_config_dict = application_dependencies_config_instance.to_dict() +# create an instance of ApplicationDependenciesConfig from a dict +application_dependencies_config_form_dict = application_dependencies_config.from_dict(application_dependencies_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/ApplicationHarnessConfig.md b/docs/model/ApplicationHarnessConfig.md new file mode 100644 index 000000000..0d6fc57ae --- /dev/null +++ b/docs/model/ApplicationHarnessConfig.md @@ -0,0 +1,50 @@ +# ApplicationHarnessConfig + +Define helm variables that allow CloudHarness to enable and configure your application's deployment + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**deployment** | [**DeploymentAutoArtifactConfig**](DeploymentAutoArtifactConfig.md) | | [optional] +**service** | [**ServiceAutoArtifactConfig**](ServiceAutoArtifactConfig.md) | | [optional] +**subdomain** | **str** | If specified, an ingress will be created at [subdomain].[.Values.domain] | [optional] +**aliases** | **List[str]** | If specified, an ingress will be created at [alias].[.Values.domain] for each alias | [optional] +**domain** | **str** | If specified, an ingress will be created at [domain] | [optional] +**dependencies** | [**ApplicationDependenciesConfig**](ApplicationDependenciesConfig.md) | | [optional] +**secured** | **bool** | When true, the application is shielded with a getekeeper | [optional] +**uri_role_mapping** | [**List[UriRoleMappingConfig]**](UriRoleMappingConfig.md) | Map uri/roles to secure with the Gatekeeper (if `secured: true`) | [optional] +**secrets** | **Dict[str, object]** | | [optional] +**use_services** | **List[str]** | Specify which services this application uses in the frontend to create proxy ingresses. e.g. ``` - name: samples ``` | [optional] +**database** | [**DatabaseDeploymentConfig**](DatabaseDeploymentConfig.md) | | [optional] +**resources** | [**List[FileResourcesConfig]**](FileResourcesConfig.md) | Application file resources. Maps from deploy/resources folder and mounts as configmaps | [optional] +**readiness_probe** | [**ApplicationProbe**](ApplicationProbe.md) | | [optional] +**startup_probe** | [**ApplicationProbe**](ApplicationProbe.md) | | [optional] +**liveness_probe** | [**ApplicationProbe**](ApplicationProbe.md) | | [optional] +**source_root** | **str** | | [optional] +**name** | **str** | Application's name. Do not edit, the value is automatically set from the application directory's name | [optional] +**jupyterhub** | [**JupyterHubConfig**](JupyterHubConfig.md) | | [optional] +**accounts** | [**ApplicationAccountsConfig**](ApplicationAccountsConfig.md) | | [optional] +**test** | [**ApplicationTestConfig**](ApplicationTestConfig.md) | | [optional] +**quotas** | **Dict[str, object]** | | [optional] + +## Example + +```python +from cloudharness_model.models.application_harness_config import ApplicationHarnessConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of ApplicationHarnessConfig from a JSON string +application_harness_config_instance = ApplicationHarnessConfig.from_json(json) +# print the JSON string representation of the object +print ApplicationHarnessConfig.to_json() + +# convert the object into a dict +application_harness_config_dict = application_harness_config_instance.to_dict() +# create an instance of ApplicationHarnessConfig from a dict +application_harness_config_form_dict = application_harness_config.from_dict(application_harness_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/ApplicationProbe.md b/docs/model/ApplicationProbe.md new file mode 100644 index 000000000..404de194e --- /dev/null +++ b/docs/model/ApplicationProbe.md @@ -0,0 +1,33 @@ +# ApplicationProbe + +Define a Kubernetes probe See also the [official documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**path** | **str** | | +**period_seconds** | **float** | | [optional] +**failure_threshold** | **float** | | [optional] +**initial_delay_seconds** | **float** | | [optional] + +## Example + +```python +from cloudharness_model.models.application_probe import ApplicationProbe + +# TODO update the JSON string below +json = "{}" +# create an instance of ApplicationProbe from a JSON string +application_probe_instance = ApplicationProbe.from_json(json) +# print the JSON string representation of the object +print ApplicationProbe.to_json() + +# convert the object into a dict +application_probe_dict = application_probe_instance.to_dict() +# create an instance of ApplicationProbe from a dict +application_probe_form_dict = application_probe.from_dict(application_probe_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/ApplicationTestConfig.md b/docs/model/ApplicationTestConfig.md new file mode 100644 index 000000000..c0922e1f6 --- /dev/null +++ b/docs/model/ApplicationTestConfig.md @@ -0,0 +1,32 @@ +# ApplicationTestConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**unit** | [**UnitTestsConfig**](UnitTestsConfig.md) | | +**api** | [**ApiTestsConfig**](ApiTestsConfig.md) | | +**e2e** | [**E2ETestsConfig**](E2ETestsConfig.md) | | + +## Example + +```python +from cloudharness_model.models.application_test_config import ApplicationTestConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of ApplicationTestConfig from a JSON string +application_test_config_instance = ApplicationTestConfig.from_json(json) +# print the JSON string representation of the object +print ApplicationTestConfig.to_json() + +# convert the object into a dict +application_test_config_dict = application_test_config_instance.to_dict() +# create an instance of ApplicationTestConfig from a dict +application_test_config_form_dict = application_test_config.from_dict(application_test_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/ApplicationUser.md b/docs/model/ApplicationUser.md new file mode 100644 index 000000000..d276a0386 --- /dev/null +++ b/docs/model/ApplicationUser.md @@ -0,0 +1,33 @@ +# ApplicationUser + +Defines a user + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**username** | **str** | | +**password** | **str** | | [optional] +**client_roles** | **List[str]** | | [optional] +**realm_roles** | **List[str]** | | [optional] + +## Example + +```python +from cloudharness_model.models.application_user import ApplicationUser + +# TODO update the JSON string below +json = "{}" +# create an instance of ApplicationUser from a JSON string +application_user_instance = ApplicationUser.from_json(json) +# print the JSON string representation of the object +print ApplicationUser.to_json() + +# convert the object into a dict +application_user_dict = application_user_instance.to_dict() +# create an instance of ApplicationUser from a dict +application_user_form_dict = application_user.from_dict(application_user_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/AutoArtifactSpec.md b/docs/model/AutoArtifactSpec.md new file mode 100644 index 000000000..f637301c0 --- /dev/null +++ b/docs/model/AutoArtifactSpec.md @@ -0,0 +1,31 @@ +# AutoArtifactSpec + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**auto** | **bool** | When true, enables automatic template | +**name** | **str** | | [optional] + +## Example + +```python +from cloudharness_model.models.auto_artifact_spec import AutoArtifactSpec + +# TODO update the JSON string below +json = "{}" +# create an instance of AutoArtifactSpec from a JSON string +auto_artifact_spec_instance = AutoArtifactSpec.from_json(json) +# print the JSON string representation of the object +print AutoArtifactSpec.to_json() + +# convert the object into a dict +auto_artifact_spec_dict = auto_artifact_spec_instance.to_dict() +# create an instance of AutoArtifactSpec from a dict +auto_artifact_spec_form_dict = auto_artifact_spec.from_dict(auto_artifact_spec_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/BackupConfig.md b/docs/model/BackupConfig.md new file mode 100644 index 000000000..9f18eb44b --- /dev/null +++ b/docs/model/BackupConfig.md @@ -0,0 +1,38 @@ +# BackupConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**active** | **bool** | | [optional] +**keep_days** | **int** | | [optional] +**keep_weeks** | **int** | | [optional] +**keep_months** | **int** | | [optional] +**schedule** | **str** | Cron expression | [optional] +**suffix** | **object** | The file suffix added to backup files | [optional] +**volumesize** | **str** | The volume size for backups (all backups share the same volume) | [optional] +**dir** | **str** | | +**resources** | [**DeploymentResourcesConf**](DeploymentResourcesConf.md) | | + +## Example + +```python +from cloudharness_model.models.backup_config import BackupConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of BackupConfig from a JSON string +backup_config_instance = BackupConfig.from_json(json) +# print the JSON string representation of the object +print BackupConfig.to_json() + +# convert the object into a dict +backup_config_dict = backup_config_instance.to_dict() +# create an instance of BackupConfig from a dict +backup_config_form_dict = backup_config.from_dict(backup_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/CDCEvent.md b/docs/model/CDCEvent.md new file mode 100644 index 000000000..faf90671d --- /dev/null +++ b/docs/model/CDCEvent.md @@ -0,0 +1,34 @@ +# CDCEvent + +A message sent to the orchestration queue. Applications can listen to these events to react to data change events happening on other applications. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**operation** | **str** | the operation on the object e.g. create / update / delete | +**uid** | **str** | the unique identifier attribute of the object | +**message_type** | **str** | the type of the message (relates to the object type) e.g. jobs | +**resource** | **Dict[str, object]** | | [optional] +**meta** | [**CDCEventMeta**](CDCEventMeta.md) | | + +## Example + +```python +from cloudharness_model.models.cdc_event import CDCEvent + +# TODO update the JSON string below +json = "{}" +# create an instance of CDCEvent from a JSON string +cdc_event_instance = CDCEvent.from_json(json) +# print the JSON string representation of the object +print CDCEvent.to_json() + +# convert the object into a dict +cdc_event_dict = cdc_event_instance.to_dict() +# create an instance of CDCEvent from a dict +cdc_event_form_dict = cdc_event.from_dict(cdc_event_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/CDCEventMeta.md b/docs/model/CDCEventMeta.md new file mode 100644 index 000000000..b3d633f06 --- /dev/null +++ b/docs/model/CDCEventMeta.md @@ -0,0 +1,34 @@ +# CDCEventMeta + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**app_name** | **str** | The name of the application/microservice sending the message | +**user** | [**User**](User.md) | | [optional] +**args** | **List[Dict[str, object]]** | the caller function arguments | [optional] +**kwargs** | **object** | the caller function keyword arguments | [optional] +**description** | **str** | General description -- for human consumption | [optional] + +## Example + +```python +from cloudharness_model.models.cdc_event_meta import CDCEventMeta + +# TODO update the JSON string below +json = "{}" +# create an instance of CDCEventMeta from a JSON string +cdc_event_meta_instance = CDCEventMeta.from_json(json) +# print the JSON string representation of the object +print CDCEventMeta.to_json() + +# convert the object into a dict +cdc_event_meta_dict = cdc_event_meta_instance.to_dict() +# create an instance of CDCEventMeta from a dict +cdc_event_meta_form_dict = cdc_event_meta.from_dict(cdc_event_meta_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/CpuMemoryConfig.md b/docs/model/CpuMemoryConfig.md new file mode 100644 index 000000000..7819d202e --- /dev/null +++ b/docs/model/CpuMemoryConfig.md @@ -0,0 +1,31 @@ +# CpuMemoryConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**cpu** | **str** | | [optional] +**memory** | **str** | | [optional] + +## Example + +```python +from cloudharness_model.models.cpu_memory_config import CpuMemoryConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of CpuMemoryConfig from a JSON string +cpu_memory_config_instance = CpuMemoryConfig.from_json(json) +# print the JSON string representation of the object +print CpuMemoryConfig.to_json() + +# convert the object into a dict +cpu_memory_config_dict = cpu_memory_config_instance.to_dict() +# create an instance of CpuMemoryConfig from a dict +cpu_memory_config_form_dict = cpu_memory_config.from_dict(cpu_memory_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/DatabaseDeploymentConfig.md b/docs/model/DatabaseDeploymentConfig.md new file mode 100644 index 000000000..45db673bf --- /dev/null +++ b/docs/model/DatabaseDeploymentConfig.md @@ -0,0 +1,40 @@ +# DatabaseDeploymentConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**auto** | **bool** | When true, enables automatic template | +**name** | **str** | | [optional] +**type** | **str** | Define the database type. One of (mongo, postgres, neo4j, sqlite3) | [optional] +**size** | **str** | Specify database disk size | [optional] +**user** | **str** | database username | [optional] +**var_pass** | **str** | Database password | [optional] +**image_ref** | **str** | Used for referencing images from the build | [optional] +**mongo** | **Dict[str, object]** | | [optional] +**postgres** | **Dict[str, object]** | | [optional] +**neo4j** | **object** | Neo4j database specific configuration | [optional] +**resources** | [**DeploymentResourcesConf**](DeploymentResourcesConf.md) | | [optional] + +## Example + +```python +from cloudharness_model.models.database_deployment_config import DatabaseDeploymentConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of DatabaseDeploymentConfig from a JSON string +database_deployment_config_instance = DatabaseDeploymentConfig.from_json(json) +# print the JSON string representation of the object +print DatabaseDeploymentConfig.to_json() + +# convert the object into a dict +database_deployment_config_dict = database_deployment_config_instance.to_dict() +# create an instance of DatabaseDeploymentConfig from a dict +database_deployment_config_form_dict = database_deployment_config.from_dict(database_deployment_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/DeploymentAutoArtifactConfig.md b/docs/model/DeploymentAutoArtifactConfig.md new file mode 100644 index 000000000..707059d07 --- /dev/null +++ b/docs/model/DeploymentAutoArtifactConfig.md @@ -0,0 +1,36 @@ +# DeploymentAutoArtifactConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**auto** | **bool** | When true, enables automatic template | +**name** | **str** | | [optional] +**port** | **str** | Deployment port | [optional] +**replicas** | **int** | Number of replicas | [optional] +**image** | **str** | Image name to use in the deployment. Leave it blank to set from the application's Docker file | [optional] +**resources** | [**DeploymentResourcesConf**](DeploymentResourcesConf.md) | | [optional] +**volume** | [**DeploymentVolumeSpec**](DeploymentVolumeSpec.md) | | [optional] + +## Example + +```python +from cloudharness_model.models.deployment_auto_artifact_config import DeploymentAutoArtifactConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of DeploymentAutoArtifactConfig from a JSON string +deployment_auto_artifact_config_instance = DeploymentAutoArtifactConfig.from_json(json) +# print the JSON string representation of the object +print DeploymentAutoArtifactConfig.to_json() + +# convert the object into a dict +deployment_auto_artifact_config_dict = deployment_auto_artifact_config_instance.to_dict() +# create an instance of DeploymentAutoArtifactConfig from a dict +deployment_auto_artifact_config_form_dict = deployment_auto_artifact_config.from_dict(deployment_auto_artifact_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/DeploymentResourcesConf.md b/docs/model/DeploymentResourcesConf.md new file mode 100644 index 000000000..7a0c10d1f --- /dev/null +++ b/docs/model/DeploymentResourcesConf.md @@ -0,0 +1,31 @@ +# DeploymentResourcesConf + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**requests** | [**CpuMemoryConfig**](CpuMemoryConfig.md) | | [optional] +**limits** | [**CpuMemoryConfig**](CpuMemoryConfig.md) | | [optional] + +## Example + +```python +from cloudharness_model.models.deployment_resources_conf import DeploymentResourcesConf + +# TODO update the JSON string below +json = "{}" +# create an instance of DeploymentResourcesConf from a JSON string +deployment_resources_conf_instance = DeploymentResourcesConf.from_json(json) +# print the JSON string representation of the object +print DeploymentResourcesConf.to_json() + +# convert the object into a dict +deployment_resources_conf_dict = deployment_resources_conf_instance.to_dict() +# create an instance of DeploymentResourcesConf from a dict +deployment_resources_conf_form_dict = deployment_resources_conf.from_dict(deployment_resources_conf_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/DeploymentVolumeSpec.md b/docs/model/DeploymentVolumeSpec.md new file mode 100644 index 000000000..66693cb82 --- /dev/null +++ b/docs/model/DeploymentVolumeSpec.md @@ -0,0 +1,34 @@ +# DeploymentVolumeSpec + +Defines a volume attached to the deployment. Automatically created the volume claim and mounts. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**auto** | **bool** | When true, enables automatic template | +**name** | **str** | | [optional] +**mountpath** | **str** | The mount path for the volume | +**size** | **object** | The volume size. E.g. 5Gi | [optional] +**usenfs** | **bool** | Set to `true` to use the nfs on the created volume and mount as ReadWriteMany. | [optional] + +## Example + +```python +from cloudharness_model.models.deployment_volume_spec import DeploymentVolumeSpec + +# TODO update the JSON string below +json = "{}" +# create an instance of DeploymentVolumeSpec from a JSON string +deployment_volume_spec_instance = DeploymentVolumeSpec.from_json(json) +# print the JSON string representation of the object +print DeploymentVolumeSpec.to_json() + +# convert the object into a dict +deployment_volume_spec_dict = deployment_volume_spec_instance.to_dict() +# create an instance of DeploymentVolumeSpec from a dict +deployment_volume_spec_form_dict = deployment_volume_spec.from_dict(deployment_volume_spec_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/E2ETestsConfig.md b/docs/model/E2ETestsConfig.md new file mode 100644 index 000000000..1f5756f2e --- /dev/null +++ b/docs/model/E2ETestsConfig.md @@ -0,0 +1,33 @@ +# E2ETestsConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**enabled** | **bool** | Enables end to end testing for this application (default: false) | +**smoketest** | **bool** | Specify whether to run the common smoke tests | +**ignore_console_errors** | **bool** | | [optional] +**ignore_request_errors** | **bool** | | [optional] + +## Example + +```python +from cloudharness_model.models.e2_e_tests_config import E2ETestsConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of E2ETestsConfig from a JSON string +e2_e_tests_config_instance = E2ETestsConfig.from_json(json) +# print the JSON string representation of the object +print E2ETestsConfig.to_json() + +# convert the object into a dict +e2_e_tests_config_dict = e2_e_tests_config_instance.to_dict() +# create an instance of E2ETestsConfig from a dict +e2_e_tests_config_form_dict = e2_e_tests_config.from_dict(e2_e_tests_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/FileResourcesConfig.md b/docs/model/FileResourcesConfig.md new file mode 100644 index 000000000..4d72981ef --- /dev/null +++ b/docs/model/FileResourcesConfig.md @@ -0,0 +1,32 @@ +# FileResourcesConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**name** | **str** | | +**src** | **str** | | +**dst** | **str** | | + +## Example + +```python +from cloudharness_model.models.file_resources_config import FileResourcesConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of FileResourcesConfig from a JSON string +file_resources_config_instance = FileResourcesConfig.from_json(json) +# print the JSON string representation of the object +print FileResourcesConfig.to_json() + +# convert the object into a dict +file_resources_config_dict = file_resources_config_instance.to_dict() +# create an instance of FileResourcesConfig from a dict +file_resources_config_form_dict = file_resources_config.from_dict(file_resources_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/GitDependencyConfig.md b/docs/model/GitDependencyConfig.md new file mode 100644 index 000000000..51779d4dd --- /dev/null +++ b/docs/model/GitDependencyConfig.md @@ -0,0 +1,32 @@ +# GitDependencyConfig + +Defines a git repo to be cloned inside the application path + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**url** | **str** | | +**branch_tag** | **str** | | +**path** | **str** | Defines the path where the repo is cloned. default: /git | [optional] + +## Example + +```python +from cloudharness_model.models.git_dependency_config import GitDependencyConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of GitDependencyConfig from a JSON string +git_dependency_config_instance = GitDependencyConfig.from_json(json) +# print the JSON string representation of the object +print GitDependencyConfig.to_json() + +# convert the object into a dict +git_dependency_config_dict = git_dependency_config_instance.to_dict() +# create an instance of GitDependencyConfig from a dict +git_dependency_config_form_dict = git_dependency_config.from_dict(git_dependency_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/HarnessMainConfig.md b/docs/model/HarnessMainConfig.md new file mode 100644 index 000000000..5cecf0529 --- /dev/null +++ b/docs/model/HarnessMainConfig.md @@ -0,0 +1,44 @@ +# HarnessMainConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**local** | **bool** | If set to true, local DNS mapping is added to pods. | +**secured_gatekeepers** | **bool** | Enables/disables Gatekeepers on secured applications. Set to false for testing/development | +**domain** | **str** | The root domain | +**namespace** | **str** | The K8s namespace. | +**mainapp** | **str** | Defines the app to map to the root domain | +**registry** | [**RegistryConfig**](RegistryConfig.md) | | [optional] +**tag** | **str** | Docker tag used to push/pull the built images. | [optional] +**apps** | [**Dict[str, ApplicationConfig]**](ApplicationConfig.md) | | +**env** | [**List[NameValue]**](NameValue.md) | Environmental variables added to all pods (deprecated, please use envmap) | [optional] +**privenv** | [**NameValue**](NameValue.md) | | [optional] +**backup** | [**BackupConfig**](BackupConfig.md) | | [optional] +**name** | **str** | Base name | [optional] +**task_images** | **Dict[str, object]** | | [optional] +**build_hash** | **str** | | [optional] +**envmap** | **Dict[str, object]** | | [optional] + +## Example + +```python +from cloudharness_model.models.harness_main_config import HarnessMainConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of HarnessMainConfig from a JSON string +harness_main_config_instance = HarnessMainConfig.from_json(json) +# print the JSON string representation of the object +print HarnessMainConfig.to_json() + +# convert the object into a dict +harness_main_config_dict = harness_main_config_instance.to_dict() +# create an instance of HarnessMainConfig from a dict +harness_main_config_form_dict = harness_main_config.from_dict(harness_main_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/IngressConfig.md b/docs/model/IngressConfig.md new file mode 100644 index 000000000..0c53184e0 --- /dev/null +++ b/docs/model/IngressConfig.md @@ -0,0 +1,33 @@ +# IngressConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**auto** | **bool** | When true, enables automatic template | +**name** | **str** | | [optional] +**ssl_redirect** | **bool** | | [optional] +**letsencrypt** | [**IngressConfigAllOfLetsencrypt**](IngressConfigAllOfLetsencrypt.md) | | [optional] + +## Example + +```python +from cloudharness_model.models.ingress_config import IngressConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of IngressConfig from a JSON string +ingress_config_instance = IngressConfig.from_json(json) +# print the JSON string representation of the object +print IngressConfig.to_json() + +# convert the object into a dict +ingress_config_dict = ingress_config_instance.to_dict() +# create an instance of IngressConfig from a dict +ingress_config_form_dict = ingress_config.from_dict(ingress_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/IngressConfigAllOfLetsencrypt.md b/docs/model/IngressConfigAllOfLetsencrypt.md new file mode 100644 index 000000000..836a9ee97 --- /dev/null +++ b/docs/model/IngressConfigAllOfLetsencrypt.md @@ -0,0 +1,30 @@ +# IngressConfigAllOfLetsencrypt + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**email** | **str** | | [optional] + +## Example + +```python +from cloudharness_model.models.ingress_config_all_of_letsencrypt import IngressConfigAllOfLetsencrypt + +# TODO update the JSON string below +json = "{}" +# create an instance of IngressConfigAllOfLetsencrypt from a JSON string +ingress_config_all_of_letsencrypt_instance = IngressConfigAllOfLetsencrypt.from_json(json) +# print the JSON string representation of the object +print IngressConfigAllOfLetsencrypt.to_json() + +# convert the object into a dict +ingress_config_all_of_letsencrypt_dict = ingress_config_all_of_letsencrypt_instance.to_dict() +# create an instance of IngressConfigAllOfLetsencrypt from a dict +ingress_config_all_of_letsencrypt_form_dict = ingress_config_all_of_letsencrypt.from_dict(ingress_config_all_of_letsencrypt_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/JupyterHubConfig.md b/docs/model/JupyterHubConfig.md new file mode 100644 index 000000000..ccc2e304a --- /dev/null +++ b/docs/model/JupyterHubConfig.md @@ -0,0 +1,33 @@ +# JupyterHubConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**args** | **List[str]** | arguments passed to the container | [optional] +**extra_config** | **Dict[str, object]** | | [optional] +**spawner_extra_config** | **Dict[str, object]** | | [optional] +**application_hook** | **object** | change the hook function (advanced) Specify the Python name of the function (full module path, the module must be installed in the Docker image) | [optional] + +## Example + +```python +from cloudharness_model.models.jupyter_hub_config import JupyterHubConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of JupyterHubConfig from a JSON string +jupyter_hub_config_instance = JupyterHubConfig.from_json(json) +# print the JSON string representation of the object +print JupyterHubConfig.to_json() + +# convert the object into a dict +jupyter_hub_config_dict = jupyter_hub_config_instance.to_dict() +# create an instance of JupyterHubConfig from a dict +jupyter_hub_config_form_dict = jupyter_hub_config.from_dict(jupyter_hub_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/NameValue.md b/docs/model/NameValue.md new file mode 100644 index 000000000..cfcf6f346 --- /dev/null +++ b/docs/model/NameValue.md @@ -0,0 +1,31 @@ +# NameValue + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**name** | **str** | | +**value** | **str** | | [optional] + +## Example + +```python +from cloudharness_model.models.name_value import NameValue + +# TODO update the JSON string below +json = "{}" +# create an instance of NameValue from a JSON string +name_value_instance = NameValue.from_json(json) +# print the JSON string representation of the object +print NameValue.to_json() + +# convert the object into a dict +name_value_dict = name_value_instance.to_dict() +# create an instance of NameValue from a dict +name_value_form_dict = name_value.from_dict(name_value_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/RegistryConfig.md b/docs/model/RegistryConfig.md new file mode 100644 index 000000000..88bbdd7b9 --- /dev/null +++ b/docs/model/RegistryConfig.md @@ -0,0 +1,31 @@ +# RegistryConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**name** | **str** | | +**secret** | **str** | Optional secret used for pulling from docker registry. | [optional] + +## Example + +```python +from cloudharness_model.models.registry_config import RegistryConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of RegistryConfig from a JSON string +registry_config_instance = RegistryConfig.from_json(json) +# print the JSON string representation of the object +print RegistryConfig.to_json() + +# convert the object into a dict +registry_config_dict = registry_config_instance.to_dict() +# create an instance of RegistryConfig from a dict +registry_config_form_dict = registry_config.from_dict(registry_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/ServiceAutoArtifactConfig.md b/docs/model/ServiceAutoArtifactConfig.md new file mode 100644 index 000000000..dc4c74d87 --- /dev/null +++ b/docs/model/ServiceAutoArtifactConfig.md @@ -0,0 +1,32 @@ +# ServiceAutoArtifactConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**auto** | **bool** | When true, enables automatic template | +**name** | **str** | | [optional] +**port** | **int** | Service port | [optional] + +## Example + +```python +from cloudharness_model.models.service_auto_artifact_config import ServiceAutoArtifactConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of ServiceAutoArtifactConfig from a JSON string +service_auto_artifact_config_instance = ServiceAutoArtifactConfig.from_json(json) +# print the JSON string representation of the object +print ServiceAutoArtifactConfig.to_json() + +# convert the object into a dict +service_auto_artifact_config_dict = service_auto_artifact_config_instance.to_dict() +# create an instance of ServiceAutoArtifactConfig from a dict +service_auto_artifact_config_form_dict = service_auto_artifact_config.from_dict(service_auto_artifact_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/UnitTestsConfig.md b/docs/model/UnitTestsConfig.md new file mode 100644 index 000000000..9aed04ebf --- /dev/null +++ b/docs/model/UnitTestsConfig.md @@ -0,0 +1,31 @@ +# UnitTestsConfig + + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**enabled** | **bool** | Enables unit tests for this application (default: true) | +**commands** | **List[str]** | Commands to run unit tests | + +## Example + +```python +from cloudharness_model.models.unit_tests_config import UnitTestsConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of UnitTestsConfig from a JSON string +unit_tests_config_instance = UnitTestsConfig.from_json(json) +# print the JSON string representation of the object +print UnitTestsConfig.to_json() + +# convert the object into a dict +unit_tests_config_dict = unit_tests_config_instance.to_dict() +# create an instance of UnitTestsConfig from a dict +unit_tests_config_form_dict = unit_tests_config.from_dict(unit_tests_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/UriRoleMappingConfig.md b/docs/model/UriRoleMappingConfig.md new file mode 100644 index 000000000..11f780731 --- /dev/null +++ b/docs/model/UriRoleMappingConfig.md @@ -0,0 +1,31 @@ +# UriRoleMappingConfig + +Defines the application Gatekeeper configuration, if enabled (i.e. `secured: true`. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**uri** | **str** | | +**roles** | **List[str]** | Roles allowed to access the present uri | + +## Example + +```python +from cloudharness_model.models.uri_role_mapping_config import UriRoleMappingConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of UriRoleMappingConfig from a JSON string +uri_role_mapping_config_instance = UriRoleMappingConfig.from_json(json) +# print the JSON string representation of the object +print UriRoleMappingConfig.to_json() + +# convert the object into a dict +uri_role_mapping_config_dict = uri_role_mapping_config_instance.to_dict() +# create an instance of UriRoleMappingConfig from a dict +uri_role_mapping_config_form_dict = uri_role_mapping_config.from_dict(uri_role_mapping_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/User.md b/docs/model/User.md new file mode 100644 index 000000000..e5864f666 --- /dev/null +++ b/docs/model/User.md @@ -0,0 +1,47 @@ +# User + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**access** | **Dict[str, object]** | | [optional] +**attributes** | **Dict[str, object]** | | [optional] +**client_roles** | **Dict[str, object]** | | [optional] +**created_timestamp** | **int** | | [optional] +**credentials** | [**List[UserCredential]**](UserCredential.md) | | [optional] +**disableable_credential_types** | **List[str]** | | [optional] +**email** | **str** | | [optional] +**email_verified** | **bool** | | [optional] +**enabled** | **bool** | | [optional] +**federation_link** | **str** | | [optional] +**first_name** | **str** | | [optional] +**groups** | **List[str]** | | [optional] +**id** | **str** | | [optional] +**last_name** | **str** | | [optional] +**realm_roles** | **List[str]** | | [optional] +**required_actions** | **List[str]** | | [optional] +**service_account_client_id** | **str** | | [optional] +**username** | **str** | | [optional] +**additional_properties** | **object** | | [optional] + +## Example + +```python +from cloudharness_model.models.user import User + +# TODO update the JSON string below +json = "{}" +# create an instance of User from a JSON string +user_instance = User.from_json(json) +# print the JSON string representation of the object +print User.to_json() + +# convert the object into a dict +user_dict = user_instance.to_dict() +# create an instance of User from a dict +user_form_dict = user.from_dict(user_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/UserCredential.md b/docs/model/UserCredential.md new file mode 100644 index 000000000..8dd7e316e --- /dev/null +++ b/docs/model/UserCredential.md @@ -0,0 +1,37 @@ +# UserCredential + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**created_date** | **int** | | [optional] +**credential_data** | **str** | | [optional] +**id** | **str** | | [optional] +**priority** | **int** | | [optional] +**secret_data** | **str** | | [optional] +**temporary** | **bool** | | [optional] +**type** | **str** | | [optional] +**user_label** | **str** | | [optional] +**value** | **str** | | [optional] + +## Example + +```python +from cloudharness_model.models.user_credential import UserCredential + +# TODO update the JSON string below +json = "{}" +# create an instance of UserCredential from a JSON string +user_credential_instance = UserCredential.from_json(json) +# print the JSON string representation of the object +print UserCredential.to_json() + +# convert the object into a dict +user_credential_dict = user_credential_instance.to_dict() +# create an instance of UserCredential from a dict +user_credential_form_dict = user_credential.from_dict(user_credential_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/UserGroup.md b/docs/model/UserGroup.md new file mode 100644 index 000000000..a8a2bf145 --- /dev/null +++ b/docs/model/UserGroup.md @@ -0,0 +1,36 @@ +# UserGroup + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**access** | **Dict[str, object]** | | [optional] +**attributes** | **Dict[str, object]** | | [optional] +**client_roles** | **Dict[str, object]** | | [optional] +**id** | **str** | | [optional] +**name** | **str** | | [optional] +**path** | **str** | | [optional] +**realm_roles** | **List[str]** | | [optional] +**sub_groups** | [**List[UserGroup]**](UserGroup.md) | | [optional] + +## Example + +```python +from cloudharness_model.models.user_group import UserGroup + +# TODO update the JSON string below +json = "{}" +# create an instance of UserGroup from a JSON string +user_group_instance = UserGroup.from_json(json) +# print the JSON string representation of the object +print UserGroup.to_json() + +# convert the object into a dict +user_group_dict = user_group_instance.to_dict() +# create an instance of UserGroup from a dict +user_group_form_dict = user_group.from_dict(user_group_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/UserRole.md b/docs/model/UserRole.md new file mode 100644 index 000000000..9e244bb11 --- /dev/null +++ b/docs/model/UserRole.md @@ -0,0 +1,35 @@ +# UserRole + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**attributes** | **Dict[str, object]** | | [optional] +**client_role** | **bool** | | [optional] +**composite** | **bool** | | [optional] +**container_id** | **str** | | [optional] +**description** | **str** | | [optional] +**id** | **str** | | [optional] +**name** | **str** | | [optional] + +## Example + +```python +from cloudharness_model.models.user_role import UserRole + +# TODO update the JSON string below +json = "{}" +# create an instance of UserRole from a JSON string +user_role_instance = UserRole.from_json(json) +# print the JSON string representation of the object +print UserRole.to_json() + +# convert the object into a dict +user_role_dict = user_role_instance.to_dict() +# create an instance of UserRole from a dict +user_role_form_dict = user_role.from_dict(user_role_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/tools/deployment-cli-tools/ch_cli_tools/openapi.py b/tools/deployment-cli-tools/ch_cli_tools/openapi.py index 978b03222..05a22b44c 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/openapi.py +++ b/tools/deployment-cli-tools/ch_cli_tools/openapi.py @@ -50,7 +50,7 @@ def generate_model(base_path=ROOT): command = f"java -jar {CODEGEN} generate -i {base_path}/libraries/models/api/openapi.yaml -g python -o {tmp_path} --skip-validate-spec -c {base_path}/libraries/models/api/config.json" os.system(command) try: - source_dir = join(tmp_path, "docs/models") + source_dir = join(tmp_path, "docs") if not os.path.exists(source_dir): os.makedirs(source_dir) From cc8f107e54abd51abcf70cd36b804bd3ee798f1e Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Tue, 30 Jul 2024 10:43:52 +0100 Subject: [PATCH 14/37] CH-91 updated base model imports to custom base model --- .../models/api_tests_config.py | 2 +- .../models/application_accounts_config.py | 2 +- .../models/application_config.py | 2 +- .../models/application_dependencies_config.py | 2 +- .../models/application_harness_config.py | 2 +- .../models/application_probe.py | 2 +- .../models/application_test_config.py | 2 +- .../models/application_user.py | 2 +- .../models/auto_artifact_spec.py | 2 +- .../models/backup_config.py | 2 +- .../cloudharness_model/models/base_model.py | 68 ------------------- .../cloudharness_model/models/cdc_event.py | 2 +- .../models/cdc_event_meta.py | 2 +- .../models/cpu_memory_config.py | 2 +- .../models/database_deployment_config.py | 2 +- .../models/deployment_auto_artifact_config.py | 2 +- .../models/deployment_resources_conf.py | 2 +- .../models/deployment_volume_spec.py | 2 +- .../models/e2_e_tests_config.py | 2 +- .../models/file_resources_config.py | 2 +- .../models/git_dependency_config.py | 2 +- .../models/harness_main_config.py | 2 +- .../models/ingress_config.py | 2 +- .../ingress_config_all_of_letsencrypt.py | 2 +- .../models/jupyter_hub_config.py | 2 +- .../cloudharness_model/models/name_value.py | 2 +- .../models/registry_config.py | 2 +- .../models/service_auto_artifact_config.py | 2 +- .../models/unit_tests_config.py | 2 +- .../models/uri_role_mapping_config.py | 2 +- .../models/cloudharness_model/models/user.py | 2 +- .../models/user_credential.py | 2 +- .../cloudharness_model/models/user_group.py | 6 +- .../cloudharness_model/models/user_role.py | 2 +- 34 files changed, 35 insertions(+), 103 deletions(-) delete mode 100644 libraries/models/cloudharness_model/models/base_model.py diff --git a/libraries/models/cloudharness_model/models/api_tests_config.py b/libraries/models/cloudharness_model/models/api_tests_config.py index a4476c08f..a7965a55b 100644 --- a/libraries/models/cloudharness_model/models/api_tests_config.py +++ b/libraries/models/cloudharness_model/models/api_tests_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/application_accounts_config.py b/libraries/models/cloudharness_model/models/application_accounts_config.py index 9a97db852..9dc8b124b 100644 --- a/libraries/models/cloudharness_model/models/application_accounts_config.py +++ b/libraries/models/cloudharness_model/models/application_accounts_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.application_user import ApplicationUser from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/application_config.py b/libraries/models/cloudharness_model/models/application_config.py index f423ee3b9..26a6c8137 100644 --- a/libraries/models/cloudharness_model/models/application_config.py +++ b/libraries/models/cloudharness_model/models/application_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.application_harness_config import ApplicationHarnessConfig from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/application_dependencies_config.py b/libraries/models/cloudharness_model/models/application_dependencies_config.py index a09df86fa..1bfd211e5 100644 --- a/libraries/models/cloudharness_model/models/application_dependencies_config.py +++ b/libraries/models/cloudharness_model/models/application_dependencies_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.git_dependency_config import GitDependencyConfig from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/application_harness_config.py b/libraries/models/cloudharness_model/models/application_harness_config.py index ad85a40bf..1921de7b2 100644 --- a/libraries/models/cloudharness_model/models/application_harness_config.py +++ b/libraries/models/cloudharness_model/models/application_harness_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.application_accounts_config import ApplicationAccountsConfig from cloudharness_model.models.application_dependencies_config import ApplicationDependenciesConfig from cloudharness_model.models.application_probe import ApplicationProbe diff --git a/libraries/models/cloudharness_model/models/application_probe.py b/libraries/models/cloudharness_model/models/application_probe.py index 75864acc3..0b5907818 100644 --- a/libraries/models/cloudharness_model/models/application_probe.py +++ b/libraries/models/cloudharness_model/models/application_probe.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/application_test_config.py b/libraries/models/cloudharness_model/models/application_test_config.py index 3ad315230..73b76e537 100644 --- a/libraries/models/cloudharness_model/models/application_test_config.py +++ b/libraries/models/cloudharness_model/models/application_test_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.api_tests_config import ApiTestsConfig from cloudharness_model.models.e2_e_tests_config import E2ETestsConfig from cloudharness_model.models.unit_tests_config import UnitTestsConfig diff --git a/libraries/models/cloudharness_model/models/application_user.py b/libraries/models/cloudharness_model/models/application_user.py index 991d8ea37..78c3479cb 100644 --- a/libraries/models/cloudharness_model/models/application_user.py +++ b/libraries/models/cloudharness_model/models/application_user.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/auto_artifact_spec.py b/libraries/models/cloudharness_model/models/auto_artifact_spec.py index c0c89ac37..1280a0554 100644 --- a/libraries/models/cloudharness_model/models/auto_artifact_spec.py +++ b/libraries/models/cloudharness_model/models/auto_artifact_spec.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/backup_config.py b/libraries/models/cloudharness_model/models/backup_config.py index 0613c70dd..b41985535 100644 --- a/libraries/models/cloudharness_model/models/backup_config.py +++ b/libraries/models/cloudharness_model/models/backup_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.deployment_resources_conf import DeploymentResourcesConf import re from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/base_model.py b/libraries/models/cloudharness_model/models/base_model.py deleted file mode 100644 index 0938bbc9b..000000000 --- a/libraries/models/cloudharness_model/models/base_model.py +++ /dev/null @@ -1,68 +0,0 @@ -import pprint - -import typing - -from cloudharness_model import util - -T = typing.TypeVar('T') - - -class Model: - # openapiTypes: The key is attribute name and the - # value is attribute type. - openapi_types: typing.Dict[str, type] = {} - - # attributeMap: The key is attribute name and the - # value is json key in definition. - attribute_map: typing.Dict[str, str] = {} - - @classmethod - def from_dict(cls: typing.Type[T], dikt) -> T: - """Returns the dict as a model""" - return util.deserialize_model(dikt, cls) - - def to_dict(self): - """Returns the model properties as a dict - - :rtype: dict - """ - result = {} - - for attr in self.openapi_types: - value = getattr(self, attr) - if isinstance(value, list): - result[attr] = list(map( - lambda x: x.to_dict() if hasattr(x, "to_dict") else x, - value - )) - elif hasattr(value, "to_dict"): - result[attr] = value.to_dict() - elif isinstance(value, dict): - result[attr] = dict(map( - lambda item: (item[0], item[1].to_dict()) - if hasattr(item[1], "to_dict") else item, - value.items() - )) - else: - result[attr] = value - - return result - - def to_str(self): - """Returns the string representation of the model - - :rtype: str - """ - return pprint.pformat(self.to_dict()) - - def __repr__(self): - """For `print` and `pprint`""" - return self.to_str() - - def __eq__(self, other): - """Returns true if both objects are equal""" - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - """Returns true if both objects are not equal""" - return not self == other diff --git a/libraries/models/cloudharness_model/models/cdc_event.py b/libraries/models/cloudharness_model/models/cdc_event.py index b8861ad15..b1db28fec 100644 --- a/libraries/models/cloudharness_model/models/cdc_event.py +++ b/libraries/models/cloudharness_model/models/cdc_event.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.cdc_event_meta import CDCEventMeta from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/cdc_event_meta.py b/libraries/models/cloudharness_model/models/cdc_event_meta.py index 78db4e05f..305912878 100644 --- a/libraries/models/cloudharness_model/models/cdc_event_meta.py +++ b/libraries/models/cloudharness_model/models/cdc_event_meta.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.user import User from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/cpu_memory_config.py b/libraries/models/cloudharness_model/models/cpu_memory_config.py index 8f4f1e705..63fcee6a8 100644 --- a/libraries/models/cloudharness_model/models/cpu_memory_config.py +++ b/libraries/models/cloudharness_model/models/cpu_memory_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/database_deployment_config.py b/libraries/models/cloudharness_model/models/database_deployment_config.py index 1be424a20..b9b7faa50 100644 --- a/libraries/models/cloudharness_model/models/database_deployment_config.py +++ b/libraries/models/cloudharness_model/models/database_deployment_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.deployment_resources_conf import DeploymentResourcesConf import re from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/deployment_auto_artifact_config.py b/libraries/models/cloudharness_model/models/deployment_auto_artifact_config.py index ab31de80b..56ef4b69d 100644 --- a/libraries/models/cloudharness_model/models/deployment_auto_artifact_config.py +++ b/libraries/models/cloudharness_model/models/deployment_auto_artifact_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.deployment_resources_conf import DeploymentResourcesConf from cloudharness_model.models.deployment_volume_spec import DeploymentVolumeSpec import re diff --git a/libraries/models/cloudharness_model/models/deployment_resources_conf.py b/libraries/models/cloudharness_model/models/deployment_resources_conf.py index 27c091484..2d122230b 100644 --- a/libraries/models/cloudharness_model/models/deployment_resources_conf.py +++ b/libraries/models/cloudharness_model/models/deployment_resources_conf.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.cpu_memory_config import CpuMemoryConfig from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/deployment_volume_spec.py b/libraries/models/cloudharness_model/models/deployment_volume_spec.py index 7fc64914a..7843eae92 100644 --- a/libraries/models/cloudharness_model/models/deployment_volume_spec.py +++ b/libraries/models/cloudharness_model/models/deployment_volume_spec.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/e2_e_tests_config.py b/libraries/models/cloudharness_model/models/e2_e_tests_config.py index 6ae48d93f..baba68df9 100644 --- a/libraries/models/cloudharness_model/models/e2_e_tests_config.py +++ b/libraries/models/cloudharness_model/models/e2_e_tests_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/file_resources_config.py b/libraries/models/cloudharness_model/models/file_resources_config.py index fff73422d..2c73b702d 100644 --- a/libraries/models/cloudharness_model/models/file_resources_config.py +++ b/libraries/models/cloudharness_model/models/file_resources_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model import re from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/git_dependency_config.py b/libraries/models/cloudharness_model/models/git_dependency_config.py index 8e3acf613..8b3808153 100644 --- a/libraries/models/cloudharness_model/models/git_dependency_config.py +++ b/libraries/models/cloudharness_model/models/git_dependency_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/harness_main_config.py b/libraries/models/cloudharness_model/models/harness_main_config.py index 6691ed073..ea8b74783 100644 --- a/libraries/models/cloudharness_model/models/harness_main_config.py +++ b/libraries/models/cloudharness_model/models/harness_main_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.application_config import ApplicationConfig from cloudharness_model.models.backup_config import BackupConfig from cloudharness_model.models.name_value import NameValue diff --git a/libraries/models/cloudharness_model/models/ingress_config.py b/libraries/models/cloudharness_model/models/ingress_config.py index e0da288f0..d0b5352d0 100644 --- a/libraries/models/cloudharness_model/models/ingress_config.py +++ b/libraries/models/cloudharness_model/models/ingress_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.ingress_config_all_of_letsencrypt import IngressConfigAllOfLetsencrypt from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/ingress_config_all_of_letsencrypt.py b/libraries/models/cloudharness_model/models/ingress_config_all_of_letsencrypt.py index 467e18a2d..a9286c070 100644 --- a/libraries/models/cloudharness_model/models/ingress_config_all_of_letsencrypt.py +++ b/libraries/models/cloudharness_model/models/ingress_config_all_of_letsencrypt.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/jupyter_hub_config.py b/libraries/models/cloudharness_model/models/jupyter_hub_config.py index 5aaa9850e..35095ce4c 100644 --- a/libraries/models/cloudharness_model/models/jupyter_hub_config.py +++ b/libraries/models/cloudharness_model/models/jupyter_hub_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/name_value.py b/libraries/models/cloudharness_model/models/name_value.py index abf07fe68..22c0f511a 100644 --- a/libraries/models/cloudharness_model/models/name_value.py +++ b/libraries/models/cloudharness_model/models/name_value.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/registry_config.py b/libraries/models/cloudharness_model/models/registry_config.py index 7ce48e9cb..8e2830c6b 100644 --- a/libraries/models/cloudharness_model/models/registry_config.py +++ b/libraries/models/cloudharness_model/models/registry_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/service_auto_artifact_config.py b/libraries/models/cloudharness_model/models/service_auto_artifact_config.py index 77bded861..4225711bd 100644 --- a/libraries/models/cloudharness_model/models/service_auto_artifact_config.py +++ b/libraries/models/cloudharness_model/models/service_auto_artifact_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/unit_tests_config.py b/libraries/models/cloudharness_model/models/unit_tests_config.py index 680d984a5..6983c7fb6 100644 --- a/libraries/models/cloudharness_model/models/unit_tests_config.py +++ b/libraries/models/cloudharness_model/models/unit_tests_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/uri_role_mapping_config.py b/libraries/models/cloudharness_model/models/uri_role_mapping_config.py index 649ae22e4..4a86884cc 100644 --- a/libraries/models/cloudharness_model/models/uri_role_mapping_config.py +++ b/libraries/models/cloudharness_model/models/uri_role_mapping_config.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model import re from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/user.py b/libraries/models/cloudharness_model/models/user.py index 0676fbae8..698ad2ce4 100644 --- a/libraries/models/cloudharness_model/models/user.py +++ b/libraries/models/cloudharness_model/models/user.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model.models.user_credential import UserCredential from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/user_credential.py b/libraries/models/cloudharness_model/models/user_credential.py index 1b692f8f9..48f77e4fa 100644 --- a/libraries/models/cloudharness_model/models/user_credential.py +++ b/libraries/models/cloudharness_model/models/user_credential.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util diff --git a/libraries/models/cloudharness_model/models/user_group.py b/libraries/models/cloudharness_model/models/user_group.py index 0cf48e994..153f84fad 100644 --- a/libraries/models/cloudharness_model/models/user_group.py +++ b/libraries/models/cloudharness_model/models/user_group.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util @@ -224,7 +224,7 @@ def realm_roles(self, realm_roles: List[str]): self._realm_roles = realm_roles @property - def sub_groups(self) -> List[UserGroup]: + def sub_groups(self) -> List['UserGroup']: """Gets the sub_groups of this UserGroup. @@ -234,7 +234,7 @@ def sub_groups(self) -> List[UserGroup]: return self._sub_groups @sub_groups.setter - def sub_groups(self, sub_groups: List[UserGroup]): + def sub_groups(self, sub_groups: List['UserGroup']): """Sets the sub_groups of this UserGroup. diff --git a/libraries/models/cloudharness_model/models/user_role.py b/libraries/models/cloudharness_model/models/user_role.py index 8cbc7d005..96be6a925 100644 --- a/libraries/models/cloudharness_model/models/user_role.py +++ b/libraries/models/cloudharness_model/models/user_role.py @@ -2,7 +2,7 @@ from typing import List, Dict # noqa: F401 -from cloudharness_model.models.base_model import Model +from cloudharness_model.models.base_model_ import Model from cloudharness_model import util From 016e0fffdba0256b7f443c3e0132671d1e1acf28 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Tue, 30 Jul 2024 11:22:09 +0100 Subject: [PATCH 15/37] CH-91 updated samples minimal values to remove implicit dependency on common --- applications/samples/deploy/values-minimal.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/samples/deploy/values-minimal.yaml b/applications/samples/deploy/values-minimal.yaml index 23f802675..ee31280d3 100644 --- a/applications/samples/deploy/values-minimal.yaml +++ b/applications/samples/deploy/values-minimal.yaml @@ -3,4 +3,5 @@ harness: dependencies: soft: [] hard: [] + use_services: [] From b8afcea21369a3da33c3a928fc4c0f816e858006 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Tue, 30 Jul 2024 13:47:36 +0100 Subject: [PATCH 16/37] CH-91 Added an extra test to ensure env and envmap work together in values definition --- .../samples/backend/samples/controllers/test_controller.py | 1 + applications/samples/deploy/values-minimal.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/samples/backend/samples/controllers/test_controller.py b/applications/samples/backend/samples/controllers/test_controller.py index 3fb922f24..ff1089736 100644 --- a/applications/samples/backend/samples/controllers/test_controller.py +++ b/applications/samples/backend/samples/controllers/test_controller.py @@ -26,6 +26,7 @@ def ping(): # noqa: E501 import os expected_environment_variables = { + 'WORKERS': '3', 'ENVIRONMENT_TEST_A': 'value', 'ENVIRONMENT_TEST_B': '123', } diff --git a/applications/samples/deploy/values-minimal.yaml b/applications/samples/deploy/values-minimal.yaml index ee31280d3..1312b943a 100644 --- a/applications/samples/deploy/values-minimal.yaml +++ b/applications/samples/deploy/values-minimal.yaml @@ -1,5 +1,5 @@ harness: - secured: true + secured: false dependencies: soft: [] hard: [] From 419910db974e281be04c69b7fab1f65f8e58e06c Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 30 Jul 2024 14:58:49 +0200 Subject: [PATCH 17/37] CH-141 merge json files --- .../webapp/frontend/package.json | 11 +++++++ .../deployment-cli-tools/ch_cli_tools/helm.py | 2 +- .../ch_cli_tools/utils.py | 32 +++++++++++++++++++ .../deployment-cli-tools/harness-application | 1 + .../tests/resources/conf-source1/a.json | 7 ++++ .../tests/resources/conf-source1/b.json | 7 ++++ .../tests/resources/conf-source2/a.json | 7 ++++ .../tests/resources/conf-source2/c.json | 7 ++++ .../deployment-cli-tools/tests/test_utils.py | 11 +++++++ 9 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 application-templates/webapp/frontend/package.json create mode 100644 tools/deployment-cli-tools/tests/resources/conf-source1/a.json create mode 100644 tools/deployment-cli-tools/tests/resources/conf-source1/b.json create mode 100644 tools/deployment-cli-tools/tests/resources/conf-source2/a.json create mode 100644 tools/deployment-cli-tools/tests/resources/conf-source2/c.json diff --git a/application-templates/webapp/frontend/package.json b/application-templates/webapp/frontend/package.json new file mode 100644 index 000000000..b8d452789 --- /dev/null +++ b/application-templates/webapp/frontend/package.json @@ -0,0 +1,11 @@ +{ + "name": "__APP_NAME__", + "scripts": { + "dev": "vite", + "start": "DOMAIN=http://localhost:5000 vite", + "start:dev": "DOMAIN=https://test.ch.metacell.us vite", + "start:local": "DOMAIN=http://samples.ch vite", + "prebuild": "eslint .", + "build": "vite build" + } +} diff --git a/tools/deployment-cli-tools/ch_cli_tools/helm.py b/tools/deployment-cli-tools/ch_cli_tools/helm.py index dc4a6cba0..2552dcbe2 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/helm.py +++ b/tools/deployment-cli-tools/ch_cli_tools/helm.py @@ -410,7 +410,7 @@ def image_tag(self, image_name, build_context_path=None, dependencies=()): ignore = set(DEFAULT_IGNORE) if os.path.exists(ignore_path): with open(ignore_path) as f: - ignore = ignore.union({line.strip() for line in f}) + ignore = ignore.union({line.strip() for line in f if line.strip() and not line.startswith('#')}) logging.info(f"Ignoring {ignore}") tag = generate_tag_from_content(build_context_path, ignore) logging.info(f"Content hash: {tag}") diff --git a/tools/deployment-cli-tools/ch_cli_tools/utils.py b/tools/deployment-cli-tools/ch_cli_tools/utils.py index 9e2cbf9eb..3ec8e6f38 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/utils.py +++ b/tools/deployment-cli-tools/ch_cli_tools/utils.py @@ -145,6 +145,8 @@ def get_template(yaml_path, base_default=False): def file_is_yaml(fname): return fname[-4:] == 'yaml' or fname[-3:] == 'yml' +def file_is_json(fname): + return fname[-4:] == 'json' def replaceindir(root_src_dir, source, replace): """ @@ -270,6 +272,14 @@ def merge_configuration_directories(source, dest): except Exception as e: logging.warning(f"Overwriting file {fdest} with {fpath}") shutil.copy2(fpath, fdest) + elif file_is_json(fpath): + try: + merge_json_files(fpath, fdest) + logging.info( + f"Merged/overridden file content of {fdest} with {fpath}") + except Exception as e: + logging.warning(f"Overwriting file {fdest} with {fpath}") + shutil.copy2(fpath, fdest) else: logging.warning(f"Overwriting file {fdest} with {fpath}") shutil.copy2(fpath, fdest) @@ -280,6 +290,28 @@ def merge_yaml_files(fname, fdest): content_src = yaml.load(f) merge_to_yaml_file(content_src, fdest) +def merge_json_files(fname, fdest): + with open(fname) as f: + content_src = json.load(f) + merge_to_json_file(content_src, fdest) + +def merge_to_json_file(content_src, fdest): + if not content_src: + return + if not exists(fdest): + merged = content_src + else: + with open(fdest) as f: + content_dest = json.load(f) + + merged = dict_merge( + content_dest, content_src) if content_dest else content_src + + if not exists(dirname(fdest)): + os.makedirs(dirname(fdest)) + with open(fdest, "w") as f: + json.dump(merged, f, indent=2) + return merged def merge_to_yaml_file(content_src, fdest): if not content_src: diff --git a/tools/deployment-cli-tools/harness-application b/tools/deployment-cli-tools/harness-application index cc626eea8..37bec8089 100644 --- a/tools/deployment-cli-tools/harness-application +++ b/tools/deployment-cli-tools/harness-application @@ -71,6 +71,7 @@ if __name__ == "__main__": shutil.move(os.path.join(app_path, args.name), os.path.join(app_path, 'frontend')) generate_ts_client(openapi_file=os.path.join(app_path, 'api/openapi.yaml')) + if 'server' in templates: with tempfile.TemporaryDirectory() as tmp_dirname: copymergedir(os.path.join(CH_ROOT, APPLICATION_TEMPLATE_PATH, template_name), tmp_dirname) diff --git a/tools/deployment-cli-tools/tests/resources/conf-source1/a.json b/tools/deployment-cli-tools/tests/resources/conf-source1/a.json new file mode 100644 index 000000000..acc95bb9c --- /dev/null +++ b/tools/deployment-cli-tools/tests/resources/conf-source1/a.json @@ -0,0 +1,7 @@ +{ + "a": "a", + "b": { + "ba": "ba", + "bc": "bc" + } +} \ No newline at end of file diff --git a/tools/deployment-cli-tools/tests/resources/conf-source1/b.json b/tools/deployment-cli-tools/tests/resources/conf-source1/b.json new file mode 100644 index 000000000..424af7c06 --- /dev/null +++ b/tools/deployment-cli-tools/tests/resources/conf-source1/b.json @@ -0,0 +1,7 @@ +{ + "a": "a", + "b": { + "ba": "ba", + "bb": "bb" + } +} \ No newline at end of file diff --git a/tools/deployment-cli-tools/tests/resources/conf-source2/a.json b/tools/deployment-cli-tools/tests/resources/conf-source2/a.json new file mode 100644 index 000000000..c7f21ebc4 --- /dev/null +++ b/tools/deployment-cli-tools/tests/resources/conf-source2/a.json @@ -0,0 +1,7 @@ +{ + "a": "a1", + "b": { + "ba": "ba1", + "bb": "bb" + } +} \ No newline at end of file diff --git a/tools/deployment-cli-tools/tests/resources/conf-source2/c.json b/tools/deployment-cli-tools/tests/resources/conf-source2/c.json new file mode 100644 index 000000000..424af7c06 --- /dev/null +++ b/tools/deployment-cli-tools/tests/resources/conf-source2/c.json @@ -0,0 +1,7 @@ +{ + "a": "a", + "b": { + "ba": "ba", + "bb": "bb" + } +} \ No newline at end of file diff --git a/tools/deployment-cli-tools/tests/test_utils.py b/tools/deployment-cli-tools/tests/test_utils.py index cbd813c1f..cade77700 100644 --- a/tools/deployment-cli-tools/tests/test_utils.py +++ b/tools/deployment-cli-tools/tests/test_utils.py @@ -47,6 +47,17 @@ def test_merge_configuration_directories(): assert a['b']['ba'] == 'ba1' assert a['b']['bb'] == 'bb' assert a['b']['bc'] == 'bc' + + assert os.path.exists(os.path.join(res_path, "a.json")) + assert os.path.exists(os.path.join(res_path, "b.json")) + assert os.path.exists(os.path.join(res_path, "c.json")) + + with open(os.path.join(res_path, "a.json")) as f: + a = json.load(f) + assert a['a'] == 'a1' + assert a['b']['ba'] == 'ba1' + assert a['b']['bb'] == 'bb' + assert a['b']['bc'] == 'bc' finally: if os.path.exists(res_path): shutil.rmtree(res_path) From 7692d9b63391a418a75c210b610a3492cc31cd1a Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 30 Jul 2024 16:37:18 +0200 Subject: [PATCH 18/37] update test requirement --- applications/common/server/test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/common/server/test-requirements.txt b/applications/common/server/test-requirements.txt index f8f951d74..051bf8404 100644 --- a/applications/common/server/test-requirements.txt +++ b/applications/common/server/test-requirements.txt @@ -5,4 +5,4 @@ Flask-Testing==0.8.0 psycopg2-binary==2.8.5 Flask-SQLAlchemy==2.4.3 SQLAlchemy==1.3.17 -requests==2.21.0 +requests>=2.21.0 From 305fd30501fe132fbd2afdc12755fcabeb013c2f Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 12 Aug 2024 12:13:19 +0100 Subject: [PATCH 19/37] CH-142 Added harness configuration for dockerfile build args --- docs/model/DockerfileConfig.md | 30 +++++++++ docs/model/HarnessMainConfig.md | 1 + libraries/models/api/openapi.yaml | 9 +++ .../cloudharness_model/models/__init__.py | 1 + .../models/dockerfile_config.py | 63 +++++++++++++++++++ .../models/harness_main_config.py | 34 +++++++++- 6 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 docs/model/DockerfileConfig.md create mode 100644 libraries/models/cloudharness_model/models/dockerfile_config.py diff --git a/docs/model/DockerfileConfig.md b/docs/model/DockerfileConfig.md new file mode 100644 index 000000000..5b1925261 --- /dev/null +++ b/docs/model/DockerfileConfig.md @@ -0,0 +1,30 @@ +# DockerfileConfig + +Configuration for a dockerfile + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**build_args** | **Dict[str, object]** | | [optional] + +## Example + +```python +from cloudharness_model.models.dockerfile_config import DockerfileConfig + +# TODO update the JSON string below +json = "{}" +# create an instance of DockerfileConfig from a JSON string +dockerfile_config_instance = DockerfileConfig.from_json(json) +# print the JSON string representation of the object +print DockerfileConfig.to_json() + +# convert the object into a dict +dockerfile_config_dict = dockerfile_config_instance.to_dict() +# create an instance of DockerfileConfig from a dict +dockerfile_config_form_dict = dockerfile_config.from_dict(dockerfile_config_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/model/HarnessMainConfig.md b/docs/model/HarnessMainConfig.md index 5cecf0529..076c6faf4 100644 --- a/docs/model/HarnessMainConfig.md +++ b/docs/model/HarnessMainConfig.md @@ -21,6 +21,7 @@ Name | Type | Description | Notes **task_images** | **Dict[str, object]** | | [optional] **build_hash** | **str** | | [optional] **envmap** | **Dict[str, object]** | | [optional] +**dockerfile** | **object** | Configuration for the dockerfile used to build the app | [optional] ## Example diff --git a/libraries/models/api/openapi.yaml b/libraries/models/api/openapi.yaml index 3b115091a..0da196b0d 100644 --- a/libraries/models/api/openapi.yaml +++ b/libraries/models/api/openapi.yaml @@ -802,6 +802,8 @@ components: envmap: $ref: '#/components/schemas/SimpleMap' description: Environmental variables added to all pods + dockerfile: + description: Configuration for the dockerfile used to build the app additionalProperties: true SimpleMap: description: '' @@ -877,3 +879,10 @@ components: - $ref: '#/components/schemas/AutoArtifactSpec' additionalAttributes: true + DockerfileConfig: + description: Configuration for a dockerfile + type: object + properties: + buildArgs: + $ref: '#/components/schemas/SimpleMap' + description: Map of build arguments to provide to the dockerfile at build time diff --git a/libraries/models/cloudharness_model/models/__init__.py b/libraries/models/cloudharness_model/models/__init__.py index 488c3e6f6..13238dc74 100644 --- a/libraries/models/cloudharness_model/models/__init__.py +++ b/libraries/models/cloudharness_model/models/__init__.py @@ -17,6 +17,7 @@ from cloudharness_model.models.deployment_auto_artifact_config import DeploymentAutoArtifactConfig from cloudharness_model.models.deployment_resources_conf import DeploymentResourcesConf from cloudharness_model.models.deployment_volume_spec import DeploymentVolumeSpec +from cloudharness_model.models.dockerfile_config import DockerfileConfig from cloudharness_model.models.e2_e_tests_config import E2ETestsConfig from cloudharness_model.models.file_resources_config import FileResourcesConfig from cloudharness_model.models.git_dependency_config import GitDependencyConfig diff --git a/libraries/models/cloudharness_model/models/dockerfile_config.py b/libraries/models/cloudharness_model/models/dockerfile_config.py new file mode 100644 index 000000000..4dde44cb3 --- /dev/null +++ b/libraries/models/cloudharness_model/models/dockerfile_config.py @@ -0,0 +1,63 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from cloudharness_model.models.base_model_ import Model +from cloudharness_model import util + + +class DockerfileConfig(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, build_args=None): # noqa: E501 + """DockerfileConfig - a model defined in OpenAPI + + :param build_args: The build_args of this DockerfileConfig. # noqa: E501 + :type build_args: Dict[str, object] + """ + self.openapi_types = { + 'build_args': Dict[str, object] + } + + self.attribute_map = { + 'build_args': 'buildArgs' + } + + self._build_args = build_args + + @classmethod + def from_dict(cls, dikt) -> 'DockerfileConfig': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The DockerfileConfig of this DockerfileConfig. # noqa: E501 + :rtype: DockerfileConfig + """ + return util.deserialize_model(dikt, cls) + + @property + def build_args(self) -> Dict[str, object]: + """Gets the build_args of this DockerfileConfig. + + # noqa: E501 + + :return: The build_args of this DockerfileConfig. + :rtype: Dict[str, object] + """ + return self._build_args + + @build_args.setter + def build_args(self, build_args: Dict[str, object]): + """Sets the build_args of this DockerfileConfig. + + # noqa: E501 + + :param build_args: The build_args of this DockerfileConfig. + :type build_args: Dict[str, object] + """ + + self._build_args = build_args diff --git a/libraries/models/cloudharness_model/models/harness_main_config.py b/libraries/models/cloudharness_model/models/harness_main_config.py index ea8b74783..5019fe549 100644 --- a/libraries/models/cloudharness_model/models/harness_main_config.py +++ b/libraries/models/cloudharness_model/models/harness_main_config.py @@ -20,7 +20,7 @@ class HarnessMainConfig(Model): Do not edit the class manually. """ - def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace=None, mainapp=None, registry=None, tag=None, apps=None, env=None, privenv=None, backup=None, name=None, task_images=None, build_hash=None, envmap=None): # noqa: E501 + def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace=None, mainapp=None, registry=None, tag=None, apps=None, env=None, privenv=None, backup=None, name=None, task_images=None, build_hash=None, envmap=None, dockerfile=None): # noqa: E501 """HarnessMainConfig - a model defined in OpenAPI :param local: The local of this HarnessMainConfig. # noqa: E501 @@ -53,6 +53,8 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= :type build_hash: str :param envmap: The envmap of this HarnessMainConfig. # noqa: E501 :type envmap: Dict[str, object] + :param dockerfile: The dockerfile of this HarnessMainConfig. # noqa: E501 + :type dockerfile: object """ self.openapi_types = { 'local': bool, @@ -69,7 +71,8 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= 'name': str, 'task_images': Dict[str, object], 'build_hash': str, - 'envmap': Dict[str, object] + 'envmap': Dict[str, object], + 'dockerfile': object } self.attribute_map = { @@ -87,7 +90,8 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= 'name': 'name', 'task_images': 'task-images', 'build_hash': 'build_hash', - 'envmap': 'envmap' + 'envmap': 'envmap', + 'dockerfile': 'dockerfile' } self._local = local @@ -105,6 +109,7 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= self._task_images = task_images self._build_hash = build_hash self._envmap = envmap + self._dockerfile = dockerfile @classmethod def from_dict(cls, dikt) -> 'HarnessMainConfig': @@ -467,3 +472,26 @@ def envmap(self, envmap: Dict[str, object]): """ self._envmap = envmap + + @property + def dockerfile(self) -> object: + """Gets the dockerfile of this HarnessMainConfig. + + Configuration for the dockerfile used to build the app # noqa: E501 + + :return: The dockerfile of this HarnessMainConfig. + :rtype: object + """ + return self._dockerfile + + @dockerfile.setter + def dockerfile(self, dockerfile: object): + """Sets the dockerfile of this HarnessMainConfig. + + Configuration for the dockerfile used to build the app # noqa: E501 + + :param dockerfile: The dockerfile of this HarnessMainConfig. + :type dockerfile: object + """ + + self._dockerfile = dockerfile From 09b194944118816881019ffad14d3c969e951e90 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 12 Aug 2024 14:39:43 +0100 Subject: [PATCH 20/37] CH-142 Updated cloud harness model to accurately match the way values are defined --- docs/model/ApplicationHarnessConfig.md | 3 + docs/model/HarnessMainConfig.md | 4 +- libraries/models/api/openapi.yaml | 346 +++++++++--------- .../models/application_harness_config.py | 92 ++++- .../models/harness_main_config.py | 66 +--- 5 files changed, 274 insertions(+), 237 deletions(-) diff --git a/docs/model/ApplicationHarnessConfig.md b/docs/model/ApplicationHarnessConfig.md index 0d6fc57ae..ed250e7e0 100644 --- a/docs/model/ApplicationHarnessConfig.md +++ b/docs/model/ApplicationHarnessConfig.md @@ -27,6 +27,9 @@ Name | Type | Description | Notes **accounts** | [**ApplicationAccountsConfig**](ApplicationAccountsConfig.md) | | [optional] **test** | [**ApplicationTestConfig**](ApplicationTestConfig.md) | | [optional] **quotas** | **Dict[str, object]** | | [optional] +**env** | [**List[NameValue]**](NameValue.md) | Environmental variables added to all containers (deprecated, please use envmap) | [optional] +**envmap** | **Dict[str, object]** | | [optional] +**dockerfile** | [**DockerfileConfig**](DockerfileConfig.md) | | [optional] ## Example diff --git a/docs/model/HarnessMainConfig.md b/docs/model/HarnessMainConfig.md index 076c6faf4..2034bcc09 100644 --- a/docs/model/HarnessMainConfig.md +++ b/docs/model/HarnessMainConfig.md @@ -14,14 +14,12 @@ Name | Type | Description | Notes **registry** | [**RegistryConfig**](RegistryConfig.md) | | [optional] **tag** | **str** | Docker tag used to push/pull the built images. | [optional] **apps** | [**Dict[str, ApplicationConfig]**](ApplicationConfig.md) | | -**env** | [**List[NameValue]**](NameValue.md) | Environmental variables added to all pods (deprecated, please use envmap) | [optional] +**env** | [**List[NameValue]**](NameValue.md) | Environmental variables added to all pods | [optional] **privenv** | [**NameValue**](NameValue.md) | | [optional] **backup** | [**BackupConfig**](BackupConfig.md) | | [optional] **name** | **str** | Base name | [optional] **task_images** | **Dict[str, object]** | | [optional] **build_hash** | **str** | | [optional] -**envmap** | **Dict[str, object]** | | [optional] -**dockerfile** | **object** | Configuration for the dockerfile used to build the app | [optional] ## Example diff --git a/libraries/models/api/openapi.yaml b/libraries/models/api/openapi.yaml index 0da196b0d..f7e74a425 100644 --- a/libraries/models/api/openapi.yaml +++ b/libraries/models/api/openapi.yaml @@ -399,112 +399,6 @@ components: description: description: General description -- for human consumption type: string - ApplicationHarnessConfig: - description: |- - Define helm variables that allow CloudHarness to enable and configure your - application's deployment - required: [] - type: object - properties: - deployment: - $ref: '#/components/schemas/DeploymentAutoArtifactConfig' - description: Defines reference deployment parameters. Values maps to k8s spec - service: - $ref: '#/components/schemas/ServiceAutoArtifactConfig' - description: Defines automatic service parameters. - subdomain: - description: 'If specified, an ingress will be created at [subdomain].[.Values.domain]' - type: string - aliases: - description: 'If specified, an ingress will be created at [alias].[.Values.domain] for each alias' - type: array - items: - type: string - domain: - description: 'If specified, an ingress will be created at [domain]' - type: string - dependencies: - $ref: '#/components/schemas/ApplicationDependenciesConfig' - description: >- - Application dependencies are used to define what is required in the deployment when - --include (-i) is used. Specify application names in the list. - secured: - description: 'When true, the application is shielded with a getekeeper' - type: boolean - uri_role_mapping: - description: 'Map uri/roles to secure with the Gatekeeper (if `secured: true`)' - type: array - items: - $ref: '#/components/schemas/UriRoleMappingConfig' - secrets: - $ref: '#/components/schemas/SimpleMap' - description: |- - Define secrets will be mounted in the deployment - - Define as - - ```yaml - secrets: - secret_name: 'value' - - ``` - - Values if left empty are randomly generated - use_services: - description: >- - Specify which services this application uses in the frontend to create proxy - ingresses. e.g. - - ``` - - - name: samples - - ``` - type: array - items: - type: string - database: - $ref: '#/components/schemas/DatabaseDeploymentConfig' - description: '' - resources: - description: |- - Application file resources. Maps from deploy/resources folder and mounts as - configmaps - type: array - items: - $ref: '#/components/schemas/FileResourcesConfig' - readinessProbe: - $ref: '#/components/schemas/ApplicationProbe' - description: Kubernetes readiness probe configuration - startupProbe: - $ref: '#/components/schemas/ApplicationProbe' - description: '' - livenessProbe: - $ref: '#/components/schemas/ApplicationProbe' - description: Kubernetes liveness probe configuration - sourceRoot: - $ref: '#/components/schemas/Filename' - description: '' - name: - description: |- - Application's name. Do not edit, the value is automatically set from the - application directory's name - type: string - jupyterhub: - $ref: '#/components/schemas/JupyterHubConfig' - description: | - Configurations specific to jupyterhub. Edit only if your application is - configured as a jupyterhub deployment - accounts: - $ref: '#/components/schemas/ApplicationAccountsConfig' - description: Define specific test users and roles for this application - test: - $ref: '#/components/schemas/ApplicationTestConfig' - description: Enable and configure automated testing for this application. - quotas: - $ref: '#/components/schemas/Quota' - description: '' - additionalProperties: true JupyterHubConfig: description: '' type: object @@ -741,70 +635,6 @@ components: name: my-files size: 5Gi usenfs: true - HarnessMainConfig: - description: '' - required: - - local - - secured_gatekeepers - - domain - - namespace - - mainapp - - apps - type: object - properties: - local: - description: 'If set to true, local DNS mapping is added to pods.' - type: boolean - secured_gatekeepers: - description: >- - Enables/disables Gatekeepers on secured applications. Set to false for - testing/development - type: boolean - domain: - description: The root domain - type: string - example: The root domain. - namespace: - description: The K8s namespace. - type: string - mainapp: - description: Defines the app to map to the root domain - type: string - registry: - $ref: '#/components/schemas/RegistryConfig' - description: '' - tag: - description: Docker tag used to push/pull the built images. - type: string - apps: - $ref: '#/components/schemas/ApplicationsConfigsMap' - description: '' - env: - description: 'Environmental variables added to all pods (deprecated, please use envmap)' - type: array - items: - $ref: '#/components/schemas/NameValue' - privenv: - $ref: '#/components/schemas/NameValue' - description: Private environmental variables added to all pods - backup: - $ref: '#/components/schemas/BackupConfig' - description: '' - name: - description: Base name - type: string - task-images: - $ref: '#/components/schemas/SimpleMap' - description: '' - build_hash: - description: '' - type: string - envmap: - $ref: '#/components/schemas/SimpleMap' - description: Environmental variables added to all pods - dockerfile: - description: Configuration for the dockerfile used to build the app - additionalProperties: true SimpleMap: description: '' type: object @@ -886,3 +716,179 @@ components: buildArgs: $ref: '#/components/schemas/SimpleMap' description: Map of build arguments to provide to the dockerfile at build time + HarnessMainConfig: + description: '' + required: + - local + - secured_gatekeepers + - domain + - namespace + - mainapp + - apps + type: object + properties: + local: + description: 'If set to true, local DNS mapping is added to pods.' + type: boolean + secured_gatekeepers: + description: >- + Enables/disables Gatekeepers on secured applications. Set to false for + testing/development + type: boolean + domain: + description: The root domain + type: string + example: The root domain. + namespace: + description: The K8s namespace. + type: string + mainapp: + description: Defines the app to map to the root domain + type: string + registry: + $ref: '#/components/schemas/RegistryConfig' + description: '' + tag: + description: Docker tag used to push/pull the built images. + type: string + apps: + $ref: '#/components/schemas/ApplicationsConfigsMap' + description: '' + env: + description: Environmental variables added to all pods + type: array + items: + $ref: '#/components/schemas/NameValue' + privenv: + $ref: '#/components/schemas/NameValue' + description: Private environmental variables added to all pods + backup: + $ref: '#/components/schemas/BackupConfig' + description: '' + name: + description: Base name + type: string + task-images: + $ref: '#/components/schemas/SimpleMap' + description: '' + build_hash: + description: '' + type: string + additionalProperties: true + ApplicationHarnessConfig: + description: |- + Define helm variables that allow CloudHarness to enable and configure your + application's deployment + required: [] + type: object + properties: + deployment: + $ref: '#/components/schemas/DeploymentAutoArtifactConfig' + description: Defines reference deployment parameters. Values maps to k8s spec + service: + $ref: '#/components/schemas/ServiceAutoArtifactConfig' + description: Defines automatic service parameters. + subdomain: + description: 'If specified, an ingress will be created at [subdomain].[.Values.domain]' + type: string + aliases: + description: 'If specified, an ingress will be created at [alias].[.Values.domain] for each alias' + type: array + items: + type: string + domain: + description: 'If specified, an ingress will be created at [domain]' + type: string + dependencies: + $ref: '#/components/schemas/ApplicationDependenciesConfig' + description: >- + Application dependencies are used to define what is required in the deployment when + --include (-i) is used. Specify application names in the list. + secured: + description: 'When true, the application is shielded with a getekeeper' + type: boolean + uri_role_mapping: + description: 'Map uri/roles to secure with the Gatekeeper (if `secured: true`)' + type: array + items: + $ref: '#/components/schemas/UriRoleMappingConfig' + secrets: + $ref: '#/components/schemas/SimpleMap' + description: |- + Define secrets will be mounted in the deployment + + Define as + + ```yaml + secrets: + secret_name: 'value' + + ``` + + Values if left empty are randomly generated + use_services: + description: >- + Specify which services this application uses in the frontend to create proxy + ingresses. e.g. + + ``` + + - name: samples + + ``` + type: array + items: + type: string + database: + $ref: '#/components/schemas/DatabaseDeploymentConfig' + description: '' + resources: + description: |- + Application file resources. Maps from deploy/resources folder and mounts as + configmaps + type: array + items: + $ref: '#/components/schemas/FileResourcesConfig' + readinessProbe: + $ref: '#/components/schemas/ApplicationProbe' + description: Kubernetes readiness probe configuration + startupProbe: + $ref: '#/components/schemas/ApplicationProbe' + description: '' + livenessProbe: + $ref: '#/components/schemas/ApplicationProbe' + description: Kubernetes liveness probe configuration + sourceRoot: + $ref: '#/components/schemas/Filename' + description: '' + name: + description: |- + Application's name. Do not edit, the value is automatically set from the + application directory's name + type: string + jupyterhub: + $ref: '#/components/schemas/JupyterHubConfig' + description: | + Configurations specific to jupyterhub. Edit only if your application is + configured as a jupyterhub deployment + accounts: + $ref: '#/components/schemas/ApplicationAccountsConfig' + description: Define specific test users and roles for this application + test: + $ref: '#/components/schemas/ApplicationTestConfig' + description: Enable and configure automated testing for this application. + quotas: + $ref: '#/components/schemas/Quota' + description: '' + env: + description: 'Environmental variables added to all containers (deprecated, please use envmap)' + type: array + items: + $ref: '#/components/schemas/NameValue' + envmap: + $ref: '#/components/schemas/SimpleMap' + description: Environmental variables added to all containers + dockerfile: + $ref: '#/components/schemas/DockerfileConfig' + description: Configuration for the dockerfile used to build the app + additionalProperties: true diff --git a/libraries/models/cloudharness_model/models/application_harness_config.py b/libraries/models/cloudharness_model/models/application_harness_config.py index 1921de7b2..264b0ebcd 100644 --- a/libraries/models/cloudharness_model/models/application_harness_config.py +++ b/libraries/models/cloudharness_model/models/application_harness_config.py @@ -9,8 +9,10 @@ from cloudharness_model.models.application_test_config import ApplicationTestConfig from cloudharness_model.models.database_deployment_config import DatabaseDeploymentConfig from cloudharness_model.models.deployment_auto_artifact_config import DeploymentAutoArtifactConfig +from cloudharness_model.models.dockerfile_config import DockerfileConfig from cloudharness_model.models.file_resources_config import FileResourcesConfig from cloudharness_model.models.jupyter_hub_config import JupyterHubConfig +from cloudharness_model.models.name_value import NameValue from cloudharness_model.models.service_auto_artifact_config import ServiceAutoArtifactConfig from cloudharness_model.models.uri_role_mapping_config import UriRoleMappingConfig import re @@ -22,8 +24,10 @@ from cloudharness_model.models.application_test_config import ApplicationTestConfig # noqa: E501 from cloudharness_model.models.database_deployment_config import DatabaseDeploymentConfig # noqa: E501 from cloudharness_model.models.deployment_auto_artifact_config import DeploymentAutoArtifactConfig # noqa: E501 +from cloudharness_model.models.dockerfile_config import DockerfileConfig # noqa: E501 from cloudharness_model.models.file_resources_config import FileResourcesConfig # noqa: E501 from cloudharness_model.models.jupyter_hub_config import JupyterHubConfig # noqa: E501 +from cloudharness_model.models.name_value import NameValue # noqa: E501 from cloudharness_model.models.service_auto_artifact_config import ServiceAutoArtifactConfig # noqa: E501 from cloudharness_model.models.uri_role_mapping_config import UriRoleMappingConfig # noqa: E501 import re # noqa: E501 @@ -34,7 +38,7 @@ class ApplicationHarnessConfig(Model): Do not edit the class manually. """ - def __init__(self, deployment=None, service=None, subdomain=None, aliases=None, domain=None, dependencies=None, secured=None, uri_role_mapping=None, secrets=None, use_services=None, database=None, resources=None, readiness_probe=None, startup_probe=None, liveness_probe=None, source_root=None, name=None, jupyterhub=None, accounts=None, test=None, quotas=None): # noqa: E501 + def __init__(self, deployment=None, service=None, subdomain=None, aliases=None, domain=None, dependencies=None, secured=None, uri_role_mapping=None, secrets=None, use_services=None, database=None, resources=None, readiness_probe=None, startup_probe=None, liveness_probe=None, source_root=None, name=None, jupyterhub=None, accounts=None, test=None, quotas=None, env=None, envmap=None, dockerfile=None): # noqa: E501 """ApplicationHarnessConfig - a model defined in OpenAPI :param deployment: The deployment of this ApplicationHarnessConfig. # noqa: E501 @@ -79,6 +83,12 @@ def __init__(self, deployment=None, service=None, subdomain=None, aliases=None, :type test: ApplicationTestConfig :param quotas: The quotas of this ApplicationHarnessConfig. # noqa: E501 :type quotas: Dict[str, object] + :param env: The env of this ApplicationHarnessConfig. # noqa: E501 + :type env: List[NameValue] + :param envmap: The envmap of this ApplicationHarnessConfig. # noqa: E501 + :type envmap: Dict[str, object] + :param dockerfile: The dockerfile of this ApplicationHarnessConfig. # noqa: E501 + :type dockerfile: DockerfileConfig """ self.openapi_types = { 'deployment': DeploymentAutoArtifactConfig, @@ -101,7 +111,10 @@ def __init__(self, deployment=None, service=None, subdomain=None, aliases=None, 'jupyterhub': JupyterHubConfig, 'accounts': ApplicationAccountsConfig, 'test': ApplicationTestConfig, - 'quotas': Dict[str, object] + 'quotas': Dict[str, object], + 'env': List[NameValue], + 'envmap': Dict[str, object], + 'dockerfile': DockerfileConfig } self.attribute_map = { @@ -125,7 +138,10 @@ def __init__(self, deployment=None, service=None, subdomain=None, aliases=None, 'jupyterhub': 'jupyterhub', 'accounts': 'accounts', 'test': 'test', - 'quotas': 'quotas' + 'quotas': 'quotas', + 'env': 'env', + 'envmap': 'envmap', + 'dockerfile': 'dockerfile' } self._deployment = deployment @@ -149,6 +165,9 @@ def __init__(self, deployment=None, service=None, subdomain=None, aliases=None, self._accounts = accounts self._test = test self._quotas = quotas + self._env = env + self._envmap = envmap + self._dockerfile = dockerfile @classmethod def from_dict(cls, dikt) -> 'ApplicationHarnessConfig': @@ -625,3 +644,70 @@ def quotas(self, quotas: Dict[str, object]): """ self._quotas = quotas + + @property + def env(self) -> List[NameValue]: + """Gets the env of this ApplicationHarnessConfig. + + Environmental variables added to all containers (deprecated, please use envmap) # noqa: E501 + + :return: The env of this ApplicationHarnessConfig. + :rtype: List[NameValue] + """ + return self._env + + @env.setter + def env(self, env: List[NameValue]): + """Sets the env of this ApplicationHarnessConfig. + + Environmental variables added to all containers (deprecated, please use envmap) # noqa: E501 + + :param env: The env of this ApplicationHarnessConfig. + :type env: List[NameValue] + """ + + self._env = env + + @property + def envmap(self) -> Dict[str, object]: + """Gets the envmap of this ApplicationHarnessConfig. + + # noqa: E501 + + :return: The envmap of this ApplicationHarnessConfig. + :rtype: Dict[str, object] + """ + return self._envmap + + @envmap.setter + def envmap(self, envmap: Dict[str, object]): + """Sets the envmap of this ApplicationHarnessConfig. + + # noqa: E501 + + :param envmap: The envmap of this ApplicationHarnessConfig. + :type envmap: Dict[str, object] + """ + + self._envmap = envmap + + @property + def dockerfile(self) -> DockerfileConfig: + """Gets the dockerfile of this ApplicationHarnessConfig. + + + :return: The dockerfile of this ApplicationHarnessConfig. + :rtype: DockerfileConfig + """ + return self._dockerfile + + @dockerfile.setter + def dockerfile(self, dockerfile: DockerfileConfig): + """Sets the dockerfile of this ApplicationHarnessConfig. + + + :param dockerfile: The dockerfile of this ApplicationHarnessConfig. + :type dockerfile: DockerfileConfig + """ + + self._dockerfile = dockerfile diff --git a/libraries/models/cloudharness_model/models/harness_main_config.py b/libraries/models/cloudharness_model/models/harness_main_config.py index 5019fe549..9075268b4 100644 --- a/libraries/models/cloudharness_model/models/harness_main_config.py +++ b/libraries/models/cloudharness_model/models/harness_main_config.py @@ -20,7 +20,7 @@ class HarnessMainConfig(Model): Do not edit the class manually. """ - def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace=None, mainapp=None, registry=None, tag=None, apps=None, env=None, privenv=None, backup=None, name=None, task_images=None, build_hash=None, envmap=None, dockerfile=None): # noqa: E501 + def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace=None, mainapp=None, registry=None, tag=None, apps=None, env=None, privenv=None, backup=None, name=None, task_images=None, build_hash=None): # noqa: E501 """HarnessMainConfig - a model defined in OpenAPI :param local: The local of this HarnessMainConfig. # noqa: E501 @@ -51,10 +51,6 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= :type task_images: Dict[str, object] :param build_hash: The build_hash of this HarnessMainConfig. # noqa: E501 :type build_hash: str - :param envmap: The envmap of this HarnessMainConfig. # noqa: E501 - :type envmap: Dict[str, object] - :param dockerfile: The dockerfile of this HarnessMainConfig. # noqa: E501 - :type dockerfile: object """ self.openapi_types = { 'local': bool, @@ -70,9 +66,7 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= 'backup': BackupConfig, 'name': str, 'task_images': Dict[str, object], - 'build_hash': str, - 'envmap': Dict[str, object], - 'dockerfile': object + 'build_hash': str } self.attribute_map = { @@ -89,9 +83,7 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= 'backup': 'backup', 'name': 'name', 'task_images': 'task-images', - 'build_hash': 'build_hash', - 'envmap': 'envmap', - 'dockerfile': 'dockerfile' + 'build_hash': 'build_hash' } self._local = local @@ -108,8 +100,6 @@ def __init__(self, local=None, secured_gatekeepers=None, domain=None, namespace= self._name = name self._task_images = task_images self._build_hash = build_hash - self._envmap = envmap - self._dockerfile = dockerfile @classmethod def from_dict(cls, dikt) -> 'HarnessMainConfig': @@ -320,7 +310,7 @@ def apps(self, apps: Dict[str, ApplicationConfig]): def env(self) -> List[NameValue]: """Gets the env of this HarnessMainConfig. - Environmental variables added to all pods (deprecated, please use envmap) # noqa: E501 + Environmental variables added to all pods # noqa: E501 :return: The env of this HarnessMainConfig. :rtype: List[NameValue] @@ -331,7 +321,7 @@ def env(self) -> List[NameValue]: def env(self, env: List[NameValue]): """Sets the env of this HarnessMainConfig. - Environmental variables added to all pods (deprecated, please use envmap) # noqa: E501 + Environmental variables added to all pods # noqa: E501 :param env: The env of this HarnessMainConfig. :type env: List[NameValue] @@ -449,49 +439,3 @@ def build_hash(self, build_hash: str): """ self._build_hash = build_hash - - @property - def envmap(self) -> Dict[str, object]: - """Gets the envmap of this HarnessMainConfig. - - # noqa: E501 - - :return: The envmap of this HarnessMainConfig. - :rtype: Dict[str, object] - """ - return self._envmap - - @envmap.setter - def envmap(self, envmap: Dict[str, object]): - """Sets the envmap of this HarnessMainConfig. - - # noqa: E501 - - :param envmap: The envmap of this HarnessMainConfig. - :type envmap: Dict[str, object] - """ - - self._envmap = envmap - - @property - def dockerfile(self) -> object: - """Gets the dockerfile of this HarnessMainConfig. - - Configuration for the dockerfile used to build the app # noqa: E501 - - :return: The dockerfile of this HarnessMainConfig. - :rtype: object - """ - return self._dockerfile - - @dockerfile.setter - def dockerfile(self, dockerfile: object): - """Sets the dockerfile of this HarnessMainConfig. - - Configuration for the dockerfile used to build the app # noqa: E501 - - :param dockerfile: The dockerfile of this HarnessMainConfig. - :type dockerfile: object - """ - - self._dockerfile = dockerfile From d0b286ad5772eb73069b02084cdf03ee3f4327c7 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 12 Aug 2024 14:56:59 +0100 Subject: [PATCH 21/37] CH-142 Added support to pull docker build args from helm values for skaffold config --- .../ch_cli_tools/skaffold.py | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/tools/deployment-cli-tools/ch_cli_tools/skaffold.py b/tools/deployment-cli-tools/ch_cli_tools/skaffold.py index e96d71294..17ce64f95 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/skaffold.py +++ b/tools/deployment-cli-tools/ch_cli_tools/skaffold.py @@ -34,17 +34,28 @@ def get_image_tag(name): builds = {} - def build_artifact(image_name, context_path, requirements=None, dockerfile_path=''): + def build_artifact( + image_name: str, + context_path: str, + requirements: list[str] | None = None, + dockerfile_path: str = '', + additional_build_args: dict[str, str] | None = None, + ) -> dict: + build_args = { + 'REGISTRY': helm_values.registry.name, + 'TAG': helm_values.tag, + 'NOCACHE': str(time.time()), + } + + if additional_build_args: + build_args.update(additional_build_args) + artifact_spec = { 'image': image_name, 'context': context_path, 'docker': { 'dockerfile': join(dockerfile_path, 'Dockerfile'), - 'buildArgs': { - 'REGISTRY': helm_values.registry.name, - 'TAG': helm_values.tag, - 'NOCACHE': str(time.time()) - }, + 'buildArgs': build_args, 'ssh': 'default' } } @@ -56,7 +67,13 @@ def build_artifact(image_name, context_path, requirements=None, dockerfile_path= base_images = set() - def process_build_dockerfile(dockerfile_path, root_path, global_context=False, requirements=None, app_name=None): + def process_build_dockerfile( + dockerfile_path: str, + root_path: str, + global_context: bool = False, + requirements: list[str] | None = None, + app_name: str | None = None + ) -> None: if app_name is None: app_name = app_name_from_path(basename(dockerfile_path)) app_key = app_name.replace("-", "_") @@ -65,12 +82,15 @@ def process_build_dockerfile(dockerfile_path, root_path, global_context=False, r builds[app_name] = context_path base_images.add(get_image_name(app_name)) + artifacts[app_name] = build_artifact( get_image_tag(app_name), context_path, dockerfile_path=relpath(dockerfile_path, output_path), - requirements=requirements or guess_build_dependencies_from_dockerfile(dockerfile_path) + requirements=requirements or guess_build_dependencies_from_dockerfile(dockerfile_path), + additional_build_args=get_additional_build_args(helm_values, app_key), ) + if app_key in helm_values.apps and helm_values.apps[app_key].harness.dependencies and helm_values.apps[app_key].harness.dependencies.git: artifacts[app_name]['hooks'] = { 'before': [git_clone_hook(conf, context_path) for conf in helm_values.apps[app_key].harness.dependencies.git] @@ -255,4 +275,14 @@ def get_image_tag(name): if not os.path.exists(os.path.dirname(vscode_launch_path)): os.makedirs(os.path.dirname(vscode_launch_path)) with open(vscode_launch_path, 'w') as f: - json.dump(vs_conf, f, indent=2, sort_keys=True) \ No newline at end of file + json.dump(vs_conf, f, indent=2, sort_keys=True) + + +def get_additional_build_args(helm_values: dict, app_key: str) -> dict[str, str] | None: + if app_key not in helm_values.apps: + return None + + if not (helm_values.apps[app_key].harness.dockerfile and helm_values.apps[app_key].harness.dockerfile.buildArgs): + return None + + return helm_values.apps[app_key].harness.dockerfile.buildArgs \ No newline at end of file From 6a550e73e27b6cefc375ad06a8f459e107f30a21 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 12 Aug 2024 16:13:47 +0100 Subject: [PATCH 22/37] CH-142 Added testing of dockerfile configuration --- applications/samples/Dockerfile | 3 +++ applications/samples/deploy/values-minimal.yaml | 4 +++- applications/samples/deploy/values.yaml | 4 ++++ tools/deployment-cli-tools/tests/test_skaffold.py | 2 ++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/applications/samples/Dockerfile b/applications/samples/Dockerfile index 2925caf5a..522de3c9e 100644 --- a/applications/samples/Dockerfile +++ b/applications/samples/Dockerfile @@ -3,6 +3,9 @@ ARG CLOUDHARNESS_FLASK FROM $CLOUDHARNESS_FRONTEND_BUILD as frontend +ARG TEST_ARGUMENT=default +RUN echo $TEST_ARGUMENT + ENV APP_DIR=/app WORKDIR ${APP_DIR} diff --git a/applications/samples/deploy/values-minimal.yaml b/applications/samples/deploy/values-minimal.yaml index 1312b943a..c6fb239a8 100644 --- a/applications/samples/deploy/values-minimal.yaml +++ b/applications/samples/deploy/values-minimal.yaml @@ -4,4 +4,6 @@ harness: soft: [] hard: [] use_services: [] - + dockerfile: + buildArgs: + TEST_ARGUMENT: 'minimal value' diff --git a/applications/samples/deploy/values.yaml b/applications/samples/deploy/values.yaml index 7dd5e2936..3d1717ec8 100644 --- a/applications/samples/deploy/values.yaml +++ b/applications/samples/deploy/values.yaml @@ -84,3 +84,7 @@ harness: - "--request-timeout=180000" - "--hypothesis-max-examples=2" - "--show-errors-tracebacks" + + dockerfile: + buildArgs: + TEST_ARGUMENT: example value \ No newline at end of file diff --git a/tools/deployment-cli-tools/tests/test_skaffold.py b/tools/deployment-cli-tools/tests/test_skaffold.py index 981aefa58..17c0832d3 100644 --- a/tools/deployment-cli-tools/tests/test_skaffold.py +++ b/tools/deployment-cli-tools/tests/test_skaffold.py @@ -81,6 +81,8 @@ def test_create_skaffold_configuration(): a for a in sk['build']['artifacts'] if a['image'] == 'reg/cloudharness/samples' ) assert os.path.samefile(samples_artifact['context'], join(CLOUDHARNESS_ROOT, 'applications/samples')) + assert 'TEST_ARGUMENT' in samples_artifact['docker']['buildArgs'] + assert samples_artifact['docker']['buildArgs']['TEST_ARGUMENT'] == 'example value' myapp_artifact = next( a for a in sk['build']['artifacts'] if a['image'] == 'reg/cloudharness/myapp') From 49f055e2c44a9c6be3d37df97f8889feaa049a8b Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 12 Aug 2024 16:21:39 +0100 Subject: [PATCH 23/37] CH-142 Fixes to try and get the code to not throw errors with python 3.9 --- tools/deployment-cli-tools/ch_cli_tools/skaffold.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/deployment-cli-tools/ch_cli_tools/skaffold.py b/tools/deployment-cli-tools/ch_cli_tools/skaffold.py index 17ce64f95..7f6ade952 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/skaffold.py +++ b/tools/deployment-cli-tools/ch_cli_tools/skaffold.py @@ -37,9 +37,9 @@ def get_image_tag(name): def build_artifact( image_name: str, context_path: str, - requirements: list[str] | None = None, + requirements: list[str] = None, dockerfile_path: str = '', - additional_build_args: dict[str, str] | None = None, + additional_build_args: dict[str, str] = None, ) -> dict: build_args = { 'REGISTRY': helm_values.registry.name, @@ -71,8 +71,8 @@ def process_build_dockerfile( dockerfile_path: str, root_path: str, global_context: bool = False, - requirements: list[str] | None = None, - app_name: str | None = None + requirements: list[str] = None, + app_name: str = None ) -> None: if app_name is None: app_name = app_name_from_path(basename(dockerfile_path)) @@ -278,7 +278,7 @@ def get_image_tag(name): json.dump(vs_conf, f, indent=2, sort_keys=True) -def get_additional_build_args(helm_values: dict, app_key: str) -> dict[str, str] | None: +def get_additional_build_args(helm_values: dict, app_key: str) -> dict[str, str]: if app_key not in helm_values.apps: return None From de6d18be3bfdb2f75fee33a3a669db73fb5ebc6b Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Tue, 27 Aug 2024 10:21:23 +0100 Subject: [PATCH 24/37] CH-142 Fixed incorrect typing --- tools/deployment-cli-tools/ch_cli_tools/skaffold.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/deployment-cli-tools/ch_cli_tools/skaffold.py b/tools/deployment-cli-tools/ch_cli_tools/skaffold.py index 7f6ade952..e2fbf1c9b 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/skaffold.py +++ b/tools/deployment-cli-tools/ch_cli_tools/skaffold.py @@ -278,7 +278,7 @@ def get_image_tag(name): json.dump(vs_conf, f, indent=2, sort_keys=True) -def get_additional_build_args(helm_values: dict, app_key: str) -> dict[str, str]: +def get_additional_build_args(helm_values: HarnessMainConfig, app_key: str) -> dict[str, str]: if app_key not in helm_values.apps: return None From 37d0ec8b63163c6f9a6a0989a36269b8fa669385 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Wed, 28 Aug 2024 11:13:03 +0100 Subject: [PATCH 25/37] CH-142 Update docs regarding dockerfile build args --- docs/applications/README.md | 2 ++ docs/build-deploy/ci-cd/README.md | 4 ++++ libraries/models/api/openapi.yaml | 9 ++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/applications/README.md b/docs/applications/README.md index da0c44fa1..1c4492fe8 100644 --- a/docs/applications/README.md +++ b/docs/applications/README.md @@ -117,6 +117,8 @@ The most important configuration entries are the following: - `use_services` (`{name, src, dst}[]`): create reverse proxy endpoints in the ingress for the listed applications on [subdomain].[Values.domain]/proxy/[name]. Useful to avoid CORS requests from frontend clients - `readinessProbe`: defines a a url to use as a readiness probe - `livenessProbe`: defines a a url to use as a liveness probe + - `dockerfile`: configuration for the dockerfile, currently only implemented in Skaffold + - `buildArgs`: a map of build arguments to provide to the dockerfile when building with Skaffold # Example code - [Sample application](../../applications/samples) is a sample web application providing working examples of deployment configuration, backend and frontend code. diff --git a/docs/build-deploy/ci-cd/README.md b/docs/build-deploy/ci-cd/README.md index 77b590241..3d5f2de9a 100644 --- a/docs/build-deploy/ci-cd/README.md +++ b/docs/build-deploy/ci-cd/README.md @@ -15,6 +15,10 @@ All you need to to is: - Run `skaffold build` - Run `skaffold run` +### Dockerfile configuration with Skaffold + +When defining an applications values you can provide details on dockerfile configuration such as build arguments. This feature is intended to support useful development use cases (e.g. conditionally running unit tests via build arguments) and should be used with caution as it can lead to different images in different deployment environments. + ## CI/CD with Codefresh [Codefresh](https://codefresh.io/) is a nice platform for CI/CD see details in the [dedicated document](./codefresh.md). \ No newline at end of file diff --git a/libraries/models/api/openapi.yaml b/libraries/models/api/openapi.yaml index f7e74a425..8dd6d7d5a 100644 --- a/libraries/models/api/openapi.yaml +++ b/libraries/models/api/openapi.yaml @@ -715,7 +715,14 @@ components: properties: buildArgs: $ref: '#/components/schemas/SimpleMap' - description: Map of build arguments to provide to the dockerfile at build time + description: >- + Map of build arguments to provide to the dockerfile at build time. + + + The use of this feature is to aid in development (e.g. not running tests on every + local build) and not for setting environment variables in different environments; + caution should be taken when using this feature as it can lead to inconsistent + behaviour across environments. HarnessMainConfig: description: '' required: From 8862ee0d0ddbc9225602c03206c2c8d0f1bdf90f Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Tue, 3 Sep 2024 14:11:18 +0100 Subject: [PATCH 26/37] CH-144 Add 10 minute timeout to skaffold template --- deployment-configuration/skaffold-template.yaml | 2 ++ tools/deployment-cli-tools/tests/test_skaffold.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/deployment-configuration/skaffold-template.yaml b/deployment-configuration/skaffold-template.yaml index 8c7b346ce..6331c4d8b 100644 --- a/deployment-configuration/skaffold-template.yaml +++ b/deployment-configuration/skaffold-template.yaml @@ -13,6 +13,8 @@ deploy: flags: upgrade: - --install + install: + - --timeout=10m releases: - name: null chartPath: deployment/helm diff --git a/tools/deployment-cli-tools/tests/test_skaffold.py b/tools/deployment-cli-tools/tests/test_skaffold.py index 17c0832d3..999ad6396 100644 --- a/tools/deployment-cli-tools/tests/test_skaffold.py +++ b/tools/deployment-cli-tools/tests/test_skaffold.py @@ -104,6 +104,10 @@ def test_create_skaffold_configuration(): assert len(sk['test'][1]['custom']) == 2 + flags = sk['deploy']['helm']['flags'] + assert '--timeout=10m' in flags['install'] + assert '--install' in flags['upgrade'] + shutil.rmtree(OUT) shutil.rmtree(BUILD_DIR) From 81247d8edf4bff5a6650ebd23723825e79a09c11 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Fri, 6 Sep 2024 11:37:42 +0100 Subject: [PATCH 27/37] CH-147 Add namespace to usesvolume labels and pod affinity selectors --- deployment-configuration/helm/templates/auto-database.yaml | 6 +++--- .../helm/templates/auto-deployments.yaml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/deployment-configuration/helm/templates/auto-database.yaml b/deployment-configuration/helm/templates/auto-database.yaml index 6ec31380d..0658a47e8 100644 --- a/deployment-configuration/helm/templates/auto-database.yaml +++ b/deployment-configuration/helm/templates/auto-database.yaml @@ -32,7 +32,7 @@ metadata: name: {{ .app.harness.database.name | quote }} namespace: {{ .root.Values.namespace }} labels: - usesvolume: {{ .app.harness.database.name }} + usesvolume: {{ .app.harness.database.name }}-{{ .root.Values.namespace }} spec: replicas: 1 selector: @@ -43,7 +43,7 @@ spec: labels: app: {{ .app.harness.database.name | quote }} service: db - usesvolume: {{ .app.harness.database.name }} + usesvolume: {{ .app.harness.database.name }}-{{ .root.Values.namespace }} spec: affinity: podAffinity: @@ -53,7 +53,7 @@ spec: - key: usesvolume operator: In values: - - {{ .app.harness.database.name }} + - {{ .app.harness.database.name }}-{{ .root.Values.namespace }} topologyKey: "kubernetes.io/hostname" containers: - name: {{ .app.harness.database.name | quote }} diff --git a/deployment-configuration/helm/templates/auto-deployments.yaml b/deployment-configuration/helm/templates/auto-deployments.yaml index 6981c2fd4..2db3714d2 100644 --- a/deployment-configuration/helm/templates/auto-deployments.yaml +++ b/deployment-configuration/helm/templates/auto-deployments.yaml @@ -7,7 +7,7 @@ metadata: labels: app: {{ .app.harness.deployment.name| quote }} {{- if .app.harness.deployment.volume }} - usesvolume: {{ .app.harness.deployment.volume.name }} + usesvolume: {{ .app.harness.deployment.volume.name }}-{{ .root.Values.namespace }} {{- end }} {{- include "deploy_utils.labels" .root | indent 4 }} spec: @@ -26,7 +26,7 @@ spec: labels: app: {{ .app.harness.deployment.name| quote }} {{- if .app.harness.deployment.volume }} - usesvolume: {{ .app.harness.deployment.volume.name }} + usesvolume: {{ .app.harness.deployment.volume.name }}-{{ .root.Values.namespace }} {{- end }} {{- include "deploy_utils.labels" .root | indent 8 }} spec: @@ -44,7 +44,7 @@ spec: - key: usesvolume operator: In values: - - {{ .app.harness.deployment.volume.name }} + - {{ .app.harness.deployment.volume.name }}-{{ .root.Values.namespace }} topologyKey: "kubernetes.io/hostname" {{- end }} {{- end }} From ddaa206a91094d76582526ecfa80424dfb7548b6 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 9 Sep 2024 16:13:33 +0100 Subject: [PATCH 28/37] CH-137 Add obsoleted label match expression to remove issues with breaking changes --- deployment-configuration/helm/templates/auto-database.yaml | 1 + deployment-configuration/helm/templates/auto-deployments.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/deployment-configuration/helm/templates/auto-database.yaml b/deployment-configuration/helm/templates/auto-database.yaml index 0658a47e8..cd7f0bdd5 100644 --- a/deployment-configuration/helm/templates/auto-database.yaml +++ b/deployment-configuration/helm/templates/auto-database.yaml @@ -53,6 +53,7 @@ spec: - key: usesvolume operator: In values: + - {{ .app.harness.database.name }} # Obsolete, kept for backwards compatability, to be removed at a later date - {{ .app.harness.database.name }}-{{ .root.Values.namespace }} topologyKey: "kubernetes.io/hostname" containers: diff --git a/deployment-configuration/helm/templates/auto-deployments.yaml b/deployment-configuration/helm/templates/auto-deployments.yaml index 2db3714d2..66c34f55f 100644 --- a/deployment-configuration/helm/templates/auto-deployments.yaml +++ b/deployment-configuration/helm/templates/auto-deployments.yaml @@ -44,6 +44,7 @@ spec: - key: usesvolume operator: In values: + - {{ .app.harness.deployment.volume.name }} # Obsolete, kept for backwards compatability, to be removed at a later date - {{ .app.harness.deployment.volume.name }}-{{ .root.Values.namespace }} topologyKey: "kubernetes.io/hostname" {{- end }} From 89db313430b8ca4f740f0bc927c8df1606f31567 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 9 Sep 2024 16:32:56 +0100 Subject: [PATCH 29/37] CH-137 Move value to secondary selector to fix deployments --- deployment-configuration/helm/templates/auto-database.yaml | 7 ++++++- .../helm/templates/auto-deployments.yaml | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/deployment-configuration/helm/templates/auto-database.yaml b/deployment-configuration/helm/templates/auto-database.yaml index cd7f0bdd5..c2fb02dd9 100644 --- a/deployment-configuration/helm/templates/auto-database.yaml +++ b/deployment-configuration/helm/templates/auto-database.yaml @@ -53,8 +53,13 @@ spec: - key: usesvolume operator: In values: - - {{ .app.harness.database.name }} # Obsolete, kept for backwards compatability, to be removed at a later date - {{ .app.harness.database.name }}-{{ .root.Values.namespace }} + - labelSelector: + matchExpressions: + - key: usesvolume + operator: In + values: + - {{ .app.harness.database.name }} # Obsolete, kept for backwards compatability, to be removed at a later date topologyKey: "kubernetes.io/hostname" containers: - name: {{ .app.harness.database.name | quote }} diff --git a/deployment-configuration/helm/templates/auto-deployments.yaml b/deployment-configuration/helm/templates/auto-deployments.yaml index 66c34f55f..8c8bc047f 100644 --- a/deployment-configuration/helm/templates/auto-deployments.yaml +++ b/deployment-configuration/helm/templates/auto-deployments.yaml @@ -44,8 +44,13 @@ spec: - key: usesvolume operator: In values: - - {{ .app.harness.deployment.volume.name }} # Obsolete, kept for backwards compatability, to be removed at a later date - {{ .app.harness.deployment.volume.name }}-{{ .root.Values.namespace }} + - labelSelector: + matchExpressions: + - key: usesvolume + operator: In + values: + - {{ .app.harness.database.name }} # Obsolete, kept for backwards compatability, to be removed at a later date topologyKey: "kubernetes.io/hostname" {{- end }} {{- end }} From b972e82dbaa68148810e02a98492c24f2e91059a Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Mon, 9 Sep 2024 18:10:19 +0100 Subject: [PATCH 30/37] CH-137 Reverting failed attempt --- deployment-configuration/helm/templates/auto-database.yaml | 5 ----- .../helm/templates/auto-deployments.yaml | 7 +------ 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/deployment-configuration/helm/templates/auto-database.yaml b/deployment-configuration/helm/templates/auto-database.yaml index c2fb02dd9..1399961a1 100644 --- a/deployment-configuration/helm/templates/auto-database.yaml +++ b/deployment-configuration/helm/templates/auto-database.yaml @@ -54,11 +54,6 @@ spec: operator: In values: - {{ .app.harness.database.name }}-{{ .root.Values.namespace }} - - labelSelector: - matchExpressions: - - key: usesvolume - operator: In - values: - {{ .app.harness.database.name }} # Obsolete, kept for backwards compatability, to be removed at a later date topologyKey: "kubernetes.io/hostname" containers: diff --git a/deployment-configuration/helm/templates/auto-deployments.yaml b/deployment-configuration/helm/templates/auto-deployments.yaml index 8c8bc047f..641d4852b 100644 --- a/deployment-configuration/helm/templates/auto-deployments.yaml +++ b/deployment-configuration/helm/templates/auto-deployments.yaml @@ -45,12 +45,7 @@ spec: operator: In values: - {{ .app.harness.deployment.volume.name }}-{{ .root.Values.namespace }} - - labelSelector: - matchExpressions: - - key: usesvolume - operator: In - values: - - {{ .app.harness.database.name }} # Obsolete, kept for backwards compatability, to be removed at a later date + - {{ .app.harness.deployment.volume.name }} # Obsolete, kept for backwards compatability, to be removed at a later date topologyKey: "kubernetes.io/hostname" {{- end }} {{- end }} From 8c2e86079374c819b5204797816b64450ddc487c Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 10 Sep 2024 12:46:31 +0200 Subject: [PATCH 31/37] CH-32 Add Neo4j browser --- applications/neo4j/.gitignore | 1 + applications/neo4j/README.md | 22 ++++++++++ .../deploy/templates/reverseProxyServer.yaml | 37 ++++++++++++++++ applications/neo4j/deploy/values.yaml | 41 ++++++++++++++++++ applications/neo4j/docs/browser-login.png | Bin 0 -> 25106 bytes .../helm/templates/auto-database-neo4j.yaml | 2 + 6 files changed, 103 insertions(+) create mode 100644 applications/neo4j/.gitignore create mode 100644 applications/neo4j/README.md create mode 100644 applications/neo4j/deploy/templates/reverseProxyServer.yaml create mode 100644 applications/neo4j/deploy/values.yaml create mode 100644 applications/neo4j/docs/browser-login.png diff --git a/applications/neo4j/.gitignore b/applications/neo4j/.gitignore new file mode 100644 index 000000000..7c5616916 --- /dev/null +++ b/applications/neo4j/.gitignore @@ -0,0 +1 @@ +helm-charts \ No newline at end of file diff --git a/applications/neo4j/README.md b/applications/neo4j/README.md new file mode 100644 index 000000000..49dadb607 --- /dev/null +++ b/applications/neo4j/README.md @@ -0,0 +1,22 @@ +# Neo4j browser helm chart + +Enable this application to deploy a Neo4j server with the neo4j browser enabled. + +## How to use +The browser will be enabled at neo4j.[DOMAIN]. + +![Neo4j browser login](docs/browser-login.png) + +The default credentials are set in the [application configuration file](deploy/values.yaml). + +It is recommended to change the password during the first login, such as: + +``` +ALTER USER default SET PASSWORD '' +``` + +## Implementation +This implementation uses the Neo4j reverse proxy server to enable usage via Ingress and http(s). + +For more information, see https://neo4j.com/docs/operations-manual/current/kubernetes/accessing-neo4j-ingress/ + diff --git a/applications/neo4j/deploy/templates/reverseProxyServer.yaml b/applications/neo4j/deploy/templates/reverseProxyServer.yaml new file mode 100644 index 000000000..f273acb96 --- /dev/null +++ b/applications/neo4j/deploy/templates/reverseProxyServer.yaml @@ -0,0 +1,37 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.apps.neo4j.harness.deployment.name }} + labels: + app: {{ .Values.apps.neo4j.harness.deployment.name }} + namespace: "{{ .Release.Namespace }}" +spec: + replicas: 1 + selector: + matchLabels: + app: {{ .Values.apps.neo4j.harness.deployment.name }} + template: + metadata: + name: {{ .Values.apps.neo4j.harness.deployment.name }} + labels: + name: {{ .Values.apps.neo4j.harness.deployment.name }} + app: {{ .Values.apps.neo4j.harness.deployment.name }} + spec: + securityContext: {{ toYaml .Values.apps.neo4j.reverseProxy.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Values.apps.neo4j.harness.deployment.name }} + image: {{ .Values.apps.neo4j.reverseProxy.image }} + imagePullPolicy: Always + securityContext: {{ toYaml .Values.apps.neo4j.reverseProxy.containerSecurityContext | nindent 12 }} + ports: + - containerPort: {{ .Values.apps.neo4j.harness.deployment.port }} + env: + - name: SERVICE_NAME + value: {{ .Values.apps.neo4j.harness.database.name }} + - name: PORT + value: {{ .Values.apps.neo4j.harness.deployment.port | quote }} + - name: DOMAIN + value: {{ .Values.apps.neo4j.reverseProxy.domain | default "cluster.local" }} + - name: NAMESPACE + value: {{ .Release.Namespace }} +--- \ No newline at end of file diff --git a/applications/neo4j/deploy/values.yaml b/applications/neo4j/deploy/values.yaml new file mode 100644 index 000000000..4a9a45a4d --- /dev/null +++ b/applications/neo4j/deploy/values.yaml @@ -0,0 +1,41 @@ +harness: + subdomain: neo4j + database: + auto: true + name: neo4j-db + type: neo4j + user: default + pass: default + deployment: + auto: false + service: + auto: true +# Parameters for reverse proxy +reverseProxy: + image: "neo4j/helm-charts-reverse-proxy:5.23" + + # Name of the kubernetes service. This service should have the ports 7474 and 7687 open. + # This could be the admin service ex: "standalone-admin" or the loadbalancer service ex: "standalone" created via the neo4j helm chart + # serviceName , namespace , domain together will form the complete k8s service url. Ex: standalone-admin.default.svc.cluster.local + # When used against a cluster ensure the service being used is pointing to all the cluster instances. + # This could be the loadbalancer from neo4j helm chart or the headless service installed via neo4j-headless-service helm chart + serviceName: "" + # default is set to cluster.local + domain: "cluster.local" + + # securityContext defines privilege and access control settings for a Container. Making sure that we dont run Neo4j as root user. + containerSecurityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 7474 + runAsGroup: 7474 + capabilities: + drop: + - all + + podSecurityContext: + runAsNonRoot: true + runAsUser: 7474 + runAsGroup: 7474 + fsGroup: 7474 + fsGroupChangePolicy: "Always" diff --git a/applications/neo4j/docs/browser-login.png b/applications/neo4j/docs/browser-login.png new file mode 100644 index 0000000000000000000000000000000000000000..86e1db1ee173602f66e72c70a99ca8398586bfc9 GIT binary patch literal 25106 zcmd?RXHZjNxGstnMX@1DN2Li!lio$73rGo}gS1ekgkDt?L?KA;O?nMANLN5QK}u)= zB81*T3oQiBitfG7{c-2azGu$Ny)!pMSy@@@TVH+O=Y5~&OV}$7B}xi93NkV>N)_c7 z+GJ!GHOa`%U%7G_IFrHm;|Tb74yvv6oU9DVumZff2$55lBO|Mbyms>X67c@2i?RWf zjO<1m>GxcxbAc5Z+3S3j7jnAZrW?~i?jU>`?(F`#isxY>0-Uo6IdXH6$*nFWQw(M1 zt3o%1-yyHRuf5!C`3Ymk=o~F6NG&LQG^5~{y^pr*szg*>cWo9h{FFr7wz?2)O80x# z%0)^@z@9sC??qsWr8XrS#U129WYd8-VI5i-^X$r18D@vHny#g)ARLu@%VDFe-w+2x zhVm*sH;QZAX zags*o{+^OC0#3=S;Kn*L#Qv|R{$2k-{dm4F|Dj)7T{HH0dN%X;cwl)dr`WweoVEXS zh_XJgD1h_N`Bd3#!3*HE)#6mfzqf^(4YFvSy6Cq^d+Ra>`o@(ttJbgXh9&Q~zG8H8 zF2EjWshwxp%R9C19X|dgiS+z?Q%7yVRt|0+=V6!uHXP+qO?{-E7N2EwKS)7zI1+r{-8Ax(%A6X!4&R*AaWt#{Qmo3+gPiS^CVPk$js#2L4na!gue%7&M6ILC6=TFQ>E1+a-% zzBov?ZyMi^iv6yP@%>}tA+-J*u9-Sox4Y{O9&9>ReeXV>pt)uSn<{a3I!S({v=e2R z4j+ZXjS550)@`bsmWeC<3A%NJ@*JOI>{*3&jMu2cK|_;-S73d!8>ZF+oa{95T8!8b zFp2Lu$9S}r8q2Ss0!>&(PFW|*PB-_#_r6R!ue7f~wOieDtru45y>hu5y9h1X{a>04 zcYZTUOn)C13sN65#u*ZGIXD~BYR~XW_H~=4rD}d^d}ph*Kx32Lh)%~HX8zLlL92vP zPa>KRuYr3&5UgV+q#P$OpJ^*GtSLtk{!X4B-Xcd8LzQQCL>KkvE$^BAb0P!J!q`J) zMvn&iNAJVGn7+;lJeYh#++~l;e=^UoeWuPEM}Vhr$I!0~dK}8r@zNo-NQD+J>;SO=Ltb zuEnEe@?%On-H#78e6ejuJ;cTHY4&H&hO17MS29Es=wVbX+S4tJzmw{`)>1HyYFi+H?#=L_z|AKu$m5zxs z@OeXQL@` z?&{HR40je1Z(lp!Vo4jl?-2uuze5EFS*X@G*VjJ_TB+bWDm&ech>V>-x<=e?)n#Kx z4wVKSdrV8PWs1&7Q5meSuBfI87{tg*mw3sT7CD!i=2X+h2u~o`rd?w084nl3yksau z(|mSK(!O(WdAhfB>l0_sz)OE_0#evi|aF3ZCQd6Usny>kIWBh>-)rLECfy`98PHsp53a;*DH3 z)8dh%-o5_Zs*wZF6sNo0F0g>lc^sw=rrdTt!eev?60XOWjJf}r8q+@6lL2L;f?w&s zl6@j#Z%Jg&u;2~jgUG$RheXg49W$F0+?r3qDB_xLr zi83~F&{nO?^PenbiRzOda%bzWcH)#9JQuxitx&aUn#c)rZjFj*8Y*$0wsL6k^(?w0 zE0f1E`ip+F;sU9q{1v}GaD)^K*+sjn_gL_}Y&Kjv-D-v@N@qq!=U7i}{b=fGo=t_V z6Tm2$T^4DhGj5MG1kdnvu}naYsOd=*R}jO|Nyb4A6e3f>W1CdA!keoI6}-Q?dK0!h zEf|e#DfEK996X_S4u8TwM^qW6+K}s2P8+V<9onNElaO=_x4uKQ5mTmI?^&OxP#Yfo z#^cO%$gd^5{&E~2qEPdK#BN2+lnd;y*LWM|^mVKKse#JM*a{uxvhm5(pE)+?BIxBg0M9-LE?C^f<_V-zKp6`p_C1zw;JTAIh zR5n>H-C1`|M5cv_u6I0D(7BV-+?>9=7^zV#TW=kk!-c;VZNvAa=`#IUN~O-X1W(z2 zUWgr0ur)u0^Ba*gca9qI8cp17Pjz(9(O{k`oXn8UHzD6>Q<+PNb_;Em(vcVoFrL=4 z?0J%F>S5T#tRb+}Qy!3K)>T5QxPlBTlV4qxcru~p>CU+?8tbFlU@EcQAS&#AF)F8e zgmZ`-vG%A?bUYgh&b8nC)bk;PW8;g;P$=_C_JCxW+?=}!qK>rpZF}oxO;r85$ZR_^OR!O0zL^3kcWQRy4Fw^zMe&04Xc|3<>}DC!USTI z>PgSg@)jhP)hC{dIF)j&&?e(?NmknoGB&(M3`OT`Vw!E9+`qoO zftjc!;We@!hgN=|ZDCc_v^;14^Xh^0v;@A;eKSUO`DA2G=%C|eZUC}wl^@SElF})o zH&oi|L69O;f4f>AIC_6?WwsX2ObC$JS~FYQI6yvLLC6l8O{HZOJF%GLVZP>0Ts_xR zH;_*x4=fdx^m7LtTks^Oloa<*ylOaW(yM_pjpiTg{*-UgTO%K{U+E9N-u-=(D`0#y z&vNN$ERiG04XOV$mAE1ralF#fSSYJ}+!ke4T!SrX-cvHGFAvj+5sXXPsW|W4m`8*k zp^ni9dn+E-@Czx6oGbRwq=A94){#gQ-XY@@E8H@3JymbWDJZW+|BWAUcjc`i=H!*x z_x}B&c`>J-nA6a}{P2P`s$mf}1ySojIp)(v41BNDKkoYeK5IZ?f)5E{{K}$iTbnM zq34e1(uY_uJs?CUOJpa@!1TfDDNZK$7<@rO_>b{9t$H)CI*J!BhMrE9DCoeA6;4mc zOipq|5LW8IaZZr5rW+eYd*1WgcMB`f6J9=Pc(8q3CyOR%oqBCT%PQ3}RfaT>KMsWj zT4UZZHJK6_r#%juxO~5v_J<HF|Bnd@Creoc$wyJ{Cr-c|Gyg_^HrxHfb>n!3E?@})UmNkL zUCYW?f7R>Yx2L^v%{OcRQd4=A0*_>1(TReN$NsBqCeD)7#G5k-lRuQ7$9$?vz#4j@ z3LEQ9CB|brq(GB0_jPzmo-3W4=^VvK;4F4zMlbwz*NIP?1KpLAN=Cyrz=BusQ%;kgI zlW2I${j7oO+G-A^@MI;I_>}#n_xlLfLg4Y-y$eu8P^rS%B)zH{rn zL%W7)OoS9aj|B0%CuPDITDLSE6B$%o07oM;X$neOd-zW8!!tKPOg<&#q491DzEV5h zTqa8b0!TJ9kLVnUg_}=1yIl5VAAJ#73B~kByBm9?WDKtHvWQ={HYE_iHuRnDkh0CQ zH@TjS0Lpu6@hA2?9CmW77G1xJAGgVHha~lgC;C z0-L%~vEOFm>N-pS4^tW$+0v0dtrbtU#)-|8?0D4mV2tl4@mbGaPm>rasmD#jr|`i8 z6|So&i2GSGuD}iQENoXWPCO_?!-ICM^f<6;P8yc6Fs!GSh0y7prZ=j@sVGI~cg$AB)E>@m3?#G8PXWF9OMRw$Y} zsz0v^UgSwq1wVu1N=Cf&CfQA!kYXW)(Ly{EiQJ3vYm7$FM9-$D&MFB};Qm+jb;$6o zf{ZGOL*r(*ej;;{zJ(koDiln;+1ELvgg8COJjO|X>)^HPn2ucj zD81;<$tO~1tr@{&C}IIh+9$yb5g1g#!P4@UL=oO~o*$?~Azte8iVI5}+Iw=`6p zuOiFSH8fJDD819hzZpLu(h32M(20 z4L^-Lh*Yhj@0P;YBj#61~q5%=Q{V1Jz)IXbUVr7!fU(L*7-gI_GUxr zW1h>~pp~J}e&3QU+L}&=4${Q}(!;`PK4`lj*qnm*TTdDFnTAx4r-f_3^@i^Wds3 z0ih)4y_de-4aXO`FR_i^1je=_&XplOb%@6y?7okJj2zM%Wmu2O`<^&AsUkj#3QFB9^p0R<9HVF4ew4rv7bm_i z>{avmj9n*sWa{+^cNy!7ZdLl3%Cl&2E-13g;f#5!yStu-UmW1YW7$$65Wm1;K}=Ne!pzcH8fR!2lf**q~WRgYY- zi$@lnP9(56w~OyoB1BT-=23Y)7M=KvT)*anSOJQ>Vnq+w?=?rXAQznSaX=f^w+otu zd1Zd0mJW%{zI3CLKtQ^^e0L9$QplERi9}ojr8r-{U&rNKfpFTClr)jQf6s)~p>=#! zs_LQ1%0*I^5!^`XV-)AEfv~jCr#n>loe#r9Px=U8Ztj`g4I#LmEPwBni>8vx>!^`9 zChLxH-=reiu_SuQrS%wh2<%M@a^f)?k{^jJak|(xAxfNNQ>iPCqXIctsfQsM$|Hlt&GN7gv~6 zCYvY;%pB{~W8cn$tT+1 z9!D&JW*+(AOz$1w+HVW=y6d7HFQ!jNa8YQ|Icyqv*oz!E zF{Frhd)U`oobA^Lv}M&NcPRTr39FR#RzRpnA8U5l(h%Ce1AX>=Cmg$FRaAENEh?QM z=q&i5BBOCC?N|znkw#j54k2u5gs^CvaPxx1VM_3}tO;+{&+i^h(MxJWu6WAqd7D>N zdJZuL%~cM&G4`jw>)x)k-Rui;l_^e_cP-00TB-YLS;sr!y(KY|FBlEO0ay~A4jT2! z&^~>>)cS+kUaR6nQZ2W?ZuUr~sQn3@AV`Ry;1>l2rwSp9a)r%|Z~7A_P*`xC}` z+>R>MP`b7sFvtM88QqqdwU)C7lENX9@;rp8QV-b2{*^*B}(^^2BY z9R8H8%riScu*Dx0f!%u1W1MOketG<;e#W&qi#`3Fr*zd~p!Cj*rb%+YE*N%%e6cIu zU@XNsfmRYcz<>T*;U#3&va1ZJn4Eb3_x92Syt|5ap3N`L*K}b9#Uh1!$U^NiUg`Zd zxy4s?HX%N^M&CwGWDV5+bLmx{P;48MWzGOkm5{u&Z$Pcq^O4gwKgOF%9TyU;G7{dA zvm484gB^NrwWxI$Bd$;4Qrl66qlPvGfh^A|HZa>>bH53&nZW8N)RIUZ2{8deTF^~C zE|CP$nK`UfNEgH%Lu%IB3gNOgs_8kDXg)2}blul!S>PeW44qqF7Ht2%GJ;qXY$uHjhbaY==-kd=#7meuOU z=1(|3$vd(mPqs36}jD` zcW$Fq6O`(WWl`aYIF1vSRjaPDha2Xu#~pB=)p=si1=+_-)kV+iVAI9qTAu-sOrk)? zB!4gW$Q6>+Bvx44>zBfcDh>pnbaDLFh1;m~G@F>wM$Ae9^LZHKCk%ot_|2)HBnfex zxFUlNFYB=fF};j_d8m)8PkZ*?GRE<^T0J;MTZ zj+*_LPLNqyhdkl}gIMvi;TSHsbXnCjq^8fI31uDPb_x%TI2=R&DNo7E_Oa!_rQ-2?6!HLPTFF2R$^iO{ZV5* zv5SE^^kXmM=7(c`#qCU7h<%5h#1obFMpA(A%K`hq`QBf?#CU@J6 zz9CD=60LiJv4Oo$)Z_N#z*cvD(|X-qgUI&j|xgfAuo!)+4ltUnVNYAb>Y<8WQ^o$0x$Ry{O zBmr5Ssyr1)B(v@xdD_?Ai}&|NdX}|VJH2GS5qiVLpXKG*Z~-KS#4dQPuxO}jEs}f^ zipRB&i=f~od7qBZseM#l@9tjfq?8idmV9OUoAPlr0-}5aUn2X^@pt9aUY>nnh`fO^C`GL0>hJ?e&etZ|&R7zLwNWFg$ z+ms_sX|&gs%wUa7I6sQk$;(^Yk2~TjeKVAv(SB8f)lLtlS}VGeA6W)MwiZh4rvyuQ zFUQ(EsaHC}1j(rnNHXPhPR<+DFA>xyw__}(p-S~5)~QC%R_X(+D+24Gnp3wdMtkzB zvtNJt47RcBU=H_ysrTz5YipNtmmGhFv8p47`>b z!+kb~)zEW{C+bxRO{xYIVd9W}mSCn`g_IgY>quYnv=p1w zZ=rjwu={(5Aq>`mr?K1dY4Z6(makzumm9_aoPDOL?mJ63s$YUlNcb&h-Z*7{&_6IZ zsT5R{m-qVeUz+wU_fR{H&w1l>z#md)Q4N#cl8(q+l7Re}<$UlPOJq8FY3JC2bTU!- zG5Q>DA=3sI_sA~eXiklR?>xr7+OrHQZtlOfu>sQ5jJ$mLvitF#9Yj=dVoByeJYc7r z18GA>wnh8YX;Mf%>8V0@cekpls+*@}`0aGE1l;OS`px;UGSR? zxYgZ^v&NyJp;VLaFGxAHw+r*#F%llDv2Pl;6(RRKZb5;xpK+R`7wiv^-uv@3NgSF7 zR5`Vu#*#!`gNZ~Uk{xJj_`}82hLisjSvm6$hM=gZEQ*%Wg|O?^QiJwpw)%?IGu^&U zed7hkF-X`Twc~g}_=)eOG{!vhHbrYItHg|PY}h9JH~#>T;tVHM>@D}pSNJ2^$?;o0 zdyL2DqzjJy(ehiQGT>fME~u?hIp}WK8lBkYOE8g+THpYWZG; zjotft2%H-}FYHc7BxJ1rrb~DL$Q52*|690f`K(r4w}CcQXyGZTd9#_qZ?nt>LNe!T;q;QmxF%@lIzRcLt4 z9s5#6q6i7jxwN~1NfYnUZw9Lq=KRh6tMM%Nx6PgRy`<`7SLMVco?R_EWloMI1fRDa zH%!wWbp%2B4Fw--IqJ{Rd~_3NKE=Zwkg4LnxTXVlOuzvr&2=uC>#NO#&0#-WQ$GEh z?{a2@$+6U8li2s6B~Z0N6K=3_=nUwUcKNIwNOnB)PGpVM=h4&5=aagnqg$WCII2aY zzI}T^d2_C-)iU z>}`dPqZ03ZJ5+|yfS1oliq@qDeYUi;jw3(Sk%>BCw=%;LKc?zasf(In5&?DgJIQi0 zg0z#)*T6Z{J&BfP4;4gttIw_j36n>F%;ZO6T{$_SD|m~_p`>%;7uSSoW|K{emCQ@N zaH$VBF1M?cIs(wZ|W6FGX7gw4NW`=>^Vxak8pi|Np`&06P znZU_rEwnFGoz3W%3mJQnP~@#vJ+>SnXz@I`%3NVSGzRYrB=k0zt`B#6p>9(>HkQiv zXP4JXN%P6Rmlz~9SplY7m6`1E9hF*J59b>%*P@-#kamQ9Tk$W@Q6uMe1q>?qI;rN? zOQ+_tK+RLHD==-8xl|v-b{Ne%{>gK$}$uc=t*ugtC=R;vL^@UX6T9%V=k3H;Hgc zu|cL5ibEHdmt@cCY>*7wx01d*g~(auXqEsIlGnps;ecs_A6p#bH?r4b8mFJjMcaY) zEE=PHdJsO{M_==R{ndBxjwzP3&y(vwf4x2(-0%-3Bv+4}G%F}dMud2eZ5K$G83=Ge zmjUbC8wzkXE)#Xq%l74`*=dViv3eW6quyUdnbs4E=Be#)dAY9aX&!DL*kD?Zv+Wl9 zl7K22iM^n8=rA%<-7DZ(|MW6FC?pB0YtGN57?pa>r>3@SbS}fMH*gJ-}2G#u3%yy z=t+W}R2_zhZ-1)9HNMz?#nZ#~*L$t>)Ha*VsXA3PHK<5r)Gw}Wka9|Vh+201W*;ih zVNOpo>?nj$@Ppx47DYyYHfk2yJownUUr+eSlR@obRtJ+%F8?-K&iN}+-*Rl7B7keT zg^b3{8)xG+v*e_pFf1Kkdejzr*mDr{kc)SlPl(mh+}x5w=BtA z`)E`*J{p3c6>E-$KXV-1e7gG6`=irvk8;o&6|Er)_UB}?nXuzXwr{I3FJSqUa+!_w z&H0lRmy#n(M>(GE?Y;lG2`H+*(@<@nQI-k)b+h2spc0PBU}Ag2V#PaZfPavt!T}#j zVZS@(D@A-{@{y{@_{J!W{1}>>Uux23S_QBN>5qgxB_&-9!nXqV)*nabm%DxI! zjCTa*a+via7khcteg(FCzAui3KLhBNyWx07m#G6SqUm4AYjjf*?P{=X9<=h2BZd*l zKmrt0!{2XeT38o)Lkb&fjxy4M(#Xk-X_(dlUWlK9-Q3&a#9_OGQhT}>G05Q*7aV^8 zv{8H0CSydqY-;Nk(c4-sF6z$t-avvUV;iA?9yI@i`!n5b%UJX4%>hdSVg${DXOyl|NCyUwGNeaZCv|C44?vDtjz|F92*cP2A|i3;^YZSK$w8Xh zDeDZP??<(V;e+HJ(W?}xORw#~x%ng#0tz$!vg~(jNh-TcCwCIf#X^9I--H;sPiPFl zz7?$9Z8k&VOsAmbuDm$?&hN|{gG(a1E1z}=e-32~(AC#!Yd}3ZuQ&=dj*x`KeM!-F zyq9dG*nu>X=t5+q-Aj$o;#lB`c80#$tAUnapGbz!nC0#(;DJ#gqq+YaJ4&9Fa7KuJ z^%_f#guQxvmm=V|K8@iH#_UGGEnwo}S{S&DwP}2h0+d=xdF+o~J>KhxXUk$Un)y_6 z%a>&j%Z5N4nBAb}HMmm)tLSGA4QC5q2%4gscwT_-%wn5GjAJ8b@++E~WPJ%0sY~V? zEJKT86HDX##rjIBhn?EBeZ6jQOE?<^T-Hy68Z zDy8D&W5t$cPXfhTs05r!WnrhyH;*LmFG(?uSuF3m7+>r35gT~8>Sfghg%Q&tiD{k; zk-Mf6EqvGy7@U{L>>X?}5H?GmV*c!;B(i9x&h;66Z4^>6B|N=h@G*5!9qbTHC8msMG_q?@F*; zoK_}Fksz|7Bg&)*KZ+NGo0tY#rA_RT*9AKb6gU0~Oz$=%>f5Cf(()r_cLm@er5^!8 zAA=7zt)rmJGx>`JL{&rGl4MGmIA;e@Mdpza1v9L|ucELc(+J&kH%Cm>KA4eEj%@LC z=zC1r_6h@vAqFP4+-xqh9PHKS{p0oK`#R>FWy-lr^`TIrI*WMZWBC(U_+e_q#scVm z?>>Fu+^W=(h%9_xZ9jlS_VZ7cg>SL;>Gf1pPHmSnX9RTl2bNZenyhG1sjzbgyxW!Q zGcB`-y+~78-Q4GJeO5FSt3+MLa3j(B#r_>K%ki_Xj@D##DJ+l)sMrJRdku*Erf2jn`1#Te3b_=&EMGnN+@Al&@)Oh9$ziu*>U4OLclb6RmeOh(5q3_bC zdehDeJ4x2;Q4UsTGwm%M23{TQcUh=Bm=s@8ADJd)ybi#S6Uvf#mjlC3ypU<&m8w*y zyod0XmG?;b;F%WvHfe~ZpU0)aPKQ`-h2t~=y^v62c%Ej)rX#S9e$XU~I3-tIwRCI^ z;pnXQkJ36fd&ICqT|R@X5}Z-~aK%C6!&LuDkpO01urg@7hAGnx)SStF!v26@>9$kE zgYaC-8n~hb^Ek>`*A`Z2Qt3K$tcW-*zeX;7>0I2VP`nctRI+!L{@6RZroP9q7;%YB z?^9*LxN&p$y~^u?FOnXRsI-NTEqq!Ttxr^{;?g&a9ja+>PE|N(?exkn8(D^&mchm^ zoght0vfyWIB16#48;>7w!X=Q~#~ayN9WC849BV)bM~eE$!rxJGXxR3|aw2WQE5c~g z-9_ykN&!AC;%gQpsLFpaI7rO<6Q^K>0~lJ0e`P7%-X5Rc#dZIRVEi^RgOM|;LiT&o zO|^>f%B$Qj?A{2TdDO9G&fcY>DT#icR}eaHX%bcSGCg6lQXTtK#zib}u;&x3lR~v< zH)qnOleJc_%i_c1egYPUvuKwdkb@JKRnilfmLy+8!e4$)?h-rsjcdg>tXfTV&c(%3VM+WBbTCfmidY&fib+dq_y!xTsZ|@Y1di#qo6$>f7)t6J8S7-7;1yb{U zo>pqKEYAq78Q8P$Jh`iV=o`!Dl3purkz-#IjZIAm$f!yi<6NaDdsOguk6pe5Poc`F9ygS+)!>6{s z{ox?H%d6Fp*S|mQfPc|%z7aQCVT3^~6FVetuBi);*7Y1sSI2)boY`og!v(fGSGBM6 zA#te{;S4Ro9x#jm+N=Et>fHb%Y`PJ#j8OL!Y_sG(kkmyi^j73cuK4e;9H1?&J$N!!rFYRLh%zjiYK+bLdni8`jxDU z>SCiQuSy0YjToITxNf!`#Z#jN6cDd*UT#m$NG|G+zfmYO=^;$~*id3DLWXIne$e@% ztJxUmzWS32=MQ1NmYRJj8s84UaN1>JbA(aU~< zMq;PE4%V1)iD^z+2hui#iZL!5!kZyH8QJ}?%6|%dvisrxDX;q97DO3aNIPw;R-86wE2p=1Yz_Q< zg84}bpw@bhR1Aj!c&BGNEjzCWrRwQP0uN+wufB`=o8bc1RELlEPDAO#Z_qd#W~RcDMuGqG>vh$_b8| zSne^Y&GAacr6bz4kXor!?BAR}RDJYBxFPu{OwP~^ zg3Kgnr5ijQLRW=>CsTU#@HxinIce!6fqQsCF+pGS@+ZCQOH+z>F2Ot)&wXCo{yR)> z)c|QZ$24JNY7X%DQAf}JDuT>Po~UfVM^)(UbsM`3AFBOA`Di;qbq~KLI2#4o!5S$Z zn=>~>11=lkG!LkOOgdSi%rliwjkcmnP?2#xMhz&MbHk%05(|ZS{Jnu~mVlX{Rb6vrfJAs_8~clm4ME<{O`uSd&NS8NV+T(YcS z@kE)Kb(w#E7M<$AUA)~@RcS2a5Y~2%Q_=*MO%s2(MmMYcr`*Y^JF}BCDFG6_^^j7N z_l4K9a}e|;$-HM@=6M__5>PK>wtHL@gKv-jz3A<>CD8J!AxkyK*66tA2O3A8*KFgW zl1um2#R%nqh32ifD0Fxy_)AOK?eUxe%aVVaJFvfivb7U9Inen#POdYV!#vj0NgSv} z^i2A2S*CHrlXk+)=-N!@Dmsnw7R{Ba^$EK!EW6>6o0fZA74PPqU zs$~zZA!<6f=`BqZ6TA&`^CUhINt!)qI(*DzY zP3!=eoD{1-#}CDW67pWwK$N1~L@T zN&dhjc&JxA?~PX9#9whgufS4EKMhV7JVF~C1E8c`ffPaW12B|>&_21pLvD2Sg^{(G zSRwaTmt{YGM32_wvQ^3jF2@!pTE7-_JwV{Paq>Owahf|Yx!W0-t)`fotGPI3uqdH` zAmhrLXI(X(?p3`kS-U0TH6B@^y|M3vj;~dX<|+=yOCc-)zQgJ=hfExNuV8uQb3q{C zSfJA$w)2%0vpCfylXmcAhFDT01kdu>_%;rA&fOPpNW-WTy!esZ`eVI5n-$jLqn_mA z?A&67{mfRh0D9CSX-9cAl%7dPPZqoVhyEupC}L+`=Lj3IYM@&JP_?X_@JZ)BbrjI* zD&1Dx0X-3RwVo{_xkd(o@t9^3mNDfu^DIn02|Oy^&53t&5@8Nx$rV`?K*Vy3n%W9# zk6sC;6rQy#;x2CuW)i-aoXZf{0+7NBHSE_lP4ZG5yK9epc7N8BKskWTO3m(?XwMxG zKvh5UcjC60TSK95JWN(5EldPaoGt7o>Z1dQHLER7{+1{HGR^&UMUF9miO}l5tnzff zW?}Zs2+%4xAIJ#4vIVeH4q)S<@q3BTFqNmsLI4dgjv@aVvOvdj5ck3%ai^1$N|4>S z7AdXtu0Tse+Wtv(fT&k|k5P*A#Yfw)&g+DoBI2TO0w6H#yeuc*qrHvP_F=P=SD(TH zNoOi@K%Z-_Yef>!z`>cnEnm)U82{k)s6iYOC!gYce5BIlRDBzJ4D9>lqDWzliU%BV z(|MXC#``=XR;(Y`f=TUdJ$jV^@Z8b%DcF$PEQ3`o1~Mu>UUZS29oxqvjV+z2WYc^> zp!)O!@A)t;tnz4OL&SsZI(6;8a-Nxn1Wp5OLa~R|*uyoAY~3Ppn@1zFX(?W(j@`cW zsgDR1fiRISeB|qNd9|v24>fxSy)-AZyg*qRIQPI{@Ok`b0zgjD?m78ZEH%$uU(4wd zri43R(wi;sd>yr&W)L(^6Y$*U4jI`kps9bp@hFQj?G*z;LK3>}VDOo1<@)vbN`ZU6 z@SRo#`}!ekn47D~n16rcU0&{OF*RGmo;ZhiOPZS<=PoHq6+LL)LQnL)ZGUW6sVccc z{n+8DQu+&4_+){UU}E|Ei`>=xFOY3q0#_MegmKyVy4(SJjnvzr#A8VU!|N!)E!v)n zGO^hNt8jnuO~)_Ul9_KGVcO(ShR(IUAfGQe@o!7sS3S1jjM?^-wwxzfM^cqr^;xbj z4j_nYL50a7+j>!3$`Pxtn@fM~zb(lc6;`^T&vrjr7i`Y$QPBfw&G1IkTEW5}>gO`e zYQBzlnwRf?;0&!$40A*+PB)7!@al=H&Qk?Rwn^7s}YW4qg`&cMPGfwJFHG6=tHBI^5mprn;O&PJ_AW6Y5|=So7b7{^()pqkVA z!%x>B25Nmd@XCJ5DxUofZbfmJX7fExK8!D;d(QOZGuNa~9xs+ejDyY2#(%VNO>cLL zzK>>{P%PCaP+*2%lk-Uf_wtbNwUfFGK+{UG-m2yL9`Yb-8V23NcX zpb!5nz;2O+bn4xi+nz5n&b6mFTML*+{W`MgmY=zdmd`t~Nv}VTeP>$S6Rx5txUXmOVg-rHyKDs={72>dYXu;{Tj6@oV^nvh0>*c_d+jAc%?{~Pb~-cEvIbs z9`up+(l(bzO;6ud1E@69g4aAJA6h`WwNXYp-R<54!a>8ovRHJD}REj>JY(-TH&@uYD2+Ho1~&bw$a#$xi;F(%k)5 zKayWLzD+8ck!gcP$@$s?y>4^_S6evp3;Q90S z0G}8aAD?G8oG0EO&_Q~3*)f6OvGqr;KS@wYMMZ@a6hLnSmxourdv^}MzrVUXnBCLY z$NH?U@9*Ujl9F+Wi3PE-cmKs~6#yyL+$;moc47_uA%Lit>`xIKt_c+NA2DlA4l5py z7f<<*$00LhH46b=?}znMpB<~kRC@CN6D%XCt9buEUXU>xE32)!`Hu;J%Xurn&(ELv z;Ud#CpXesg86XRbZ@zwhX{4PYG#8qhnp9uDbQk%{5tA9`=H{*dqd;*vIQ$tfXJ}Y1 zT(|(dk?`FsAW^;3G?p>XvtD&gTp@dF5){;;kt&u2j7XYn(98rNw0)};|MhETd;1HZ z7`w@8J0KVo_^Hk(6)#5l7m=%`Zg?7c5Te5C-?}_*8?bN&6^#!`wxS zmhW5=wDe&D?zuwBy6_5;$gA?bb?10Z?U@iM6(EghX=N!kSuE89_du9F0^pgU0k7G2 zAiw}13aB`aq2^DQ_yCI!>fR9%NHkRP2}}5rQUuU>QgrCzLxN8sStR7by1<#wPtr3s z94N&7XpePs(1tgc8TOawSS@J7l+z>Tz56$L`YFJ zOls8jt0&0tr;1Z^UB8&M9`m@+BztPo_OKY@N-ysm~xpq}+j*1-V z=cHH#8M?tH|3D&9oeNaw#+dchFgcgdw+lF5DhO}9!mo~IwgnJjf$s!vnC2XQY$qZg zxn-LvxdB<$F%L9291lo=Mtp5|MXFnyqNu}7jsVm4;{{1BK@+|EFks&w&YF>Y&?&VO zITgadGNr5zu4nbQIFjutJf_-%9IVt;(KE-UIEF2nhu+4e zg>7#|JrPofsN!>^=kv<#<)4QW0}hCxDz=)7?tP=u1qvMn8TDXvw$cTKxa&S~RU=b` zAqJoRg|sEdy@(-cK!fqU^{=PAMfmzgI#yE6OVLEF&aM9rRkksE=8wnWv0|eOG4r6~ zCy>a}>f8sJLjXw_^LkaB!A0cbr5lkQag`sHwX)w`etj)2&{+gUooFp-V;2K=(60cN z{tpNp0A_xe9P&td^wci)mM`9=m0Lkxx|-0UpTT38wrXrUUlJww4vS<$7sRec;kbQF z>#I1Q1f*BBFSS}t+i8pwyc?q#LpR@^kFI`TV#c4cQ?xNQ%omi^3j{J`Ur82MzM}P_ z!;M>Omf>BWVgvMlz7uZ!Mnu&YY|y;>aF4 z%y#U=OO;e6Z!xfw;LR5uLqRFmHX0~%bG$d3!ikf z1XWTcDYf0vsjsqaQmtacEE@YrDNytce5q>Oj!!NSMPGkZ{2NFeEbgTHqc}B%+X7ML zK#bz-cP&zV)!u2sfXmq_(2BJ`gwDwzu4Eo$jo9r1o6Dy+B3^Y7rGS7_{mt5T7q%Nz zr;57kJTy65-kNyc&&4V|oq^?I#*2RDKnQ8w;c27#SPO-(4DzYygVl@40j5PAuT8tE+|7 zQ$+eFA_V>lg-{p_Jed5ZJs^$%q)0#S^Sg>d-5MEJkQ zc>oAR)dRSbHwMUN3ocEGJpGj`3H2?Qa4}X`rx+|zV>xEF;0Y7HReqM^)ANVxN zF=v+WPes%oxU)v>&MWoq61|A2>k_ck%A`o-tFg#G(tleFt$tIapsGr6b-29zh1yjh zTR_%v7noz_#$imZfV_tz+ZU7}JN`Ia4`iiVFk>j&Vu}-T)a{_cYppptmUrHOZHONm zWpw@S2+>17?bxoCxgF$#rEx_2S$x_SIyET@++yPKL^SB1fT<0)Rr6uVvgk-Qn+%S% z8rQE-`Vu}H)=w>u7G+*U#BYPg_n9GemmOsFGKh3ex*keaK4fGv*AQ=}i_H1=Gvwa? z%uM&&6o&|QTqU`q!&&(6A@yq`<`LE7&Ch^6`8j`8H}-~gvc7i}b)RXKM#DlQPLpd? z<8vTtBS&9rn$B-b?-d-~a(0AUy|!}iJmmn7A5;2?O7jqZOkslkKy&@Shp+Wnjst>{ zl%jsD14yBR&aOdN)vAT-Mycxu?m<*6r`n@ukbRXOyTXM?C` z?(ke;)(pPqXeeQ2)>AoE;KDwRdT0liD7{Rur49P{bkw7u71Clhcup0cry)HxQHVsA z8cGg-S7g*o9ves~hCvP#?_DPQLvhf0jc=J;_VC?ksZsvs=BA6Emsc(6xRW`^7>#iH zVn~j?KpLi#omgP_+G&zz;d)_Qd+o`wE(dc;^txN?!&*1j1YWoAP*Cez3#9w$-nwyK zyBd+FlNPBMulZM>lkxJVOi7Jkge-4!!!zx7ObFP||4?A5{tU?n5zT{DTiL`o4GF;% zoD5}Rm++fefEowu=tZSVl#R88iyK;RXDce-ZGJ>5zUh6xMV!0mBy0dVD!R+NzzZMc zg<5qF!kW0e%b%ed`m3%)#shMtB>PhDov_?J)vi z20-dII@WUPL4xBXjSisclL6Kn@H6d&3HYmJYNHfgb}%C(LxsaHkmPIIZ918s7f^oAxqQu^$D=q{ZbROWZFSLx{%K~nTQG^z zV%cs-r#t0@Q76ApO{4p!m`+lB#1GRfNYNtd)TfT`VN5ccB>zV@*BRDSwzU}tJL*-; zH6kF=yV9jPVug&p!K{z1Di)^{zE7es3cp)$9OmG<`t8z4ZJ6% zL(4O8>MQshxu^Mg+_Df4Kn2tWS}i02ic_!+@tgmU?8thy_Dj0}g>4XGj``g6EigHh zoux9?w#Jb&5M+B>nVk7H_VrRylLVu@}`BU}5=rFUKO{6PD_V%AXAsx~DSsGEc7xOefXSIFqoD6<&-z+}g zob@`d;e)~pX=`)GyISOKuUzvTbtb6_V*8}5R}lWm)*X%bxo18eG|@i!ylOd9?!0YrR(ZUcZ%ToUVoVhv%y zOOFJE4AJkkm6iVBCqno&v%urqs#JF@#U+;Q;PN4PoC(N$urb-o6Zz=~z@y@Faz-!= zJ4?QeOj+t6u>2eO@O|ft9@+IzKOj2$?+53*0zC0hyu2A`dS+K4?I1r$q?}8%VJ^LE z5UYlce+@t^BVq(*}TIW|ALaIyyGG&sCk5X-?q%aOexwbnu7SIE844T%v zU2~3PH3paTOBj>mOOtok*yM6slytuU2GPG!4f*IyyW4cr#EGN*)AbdFM=gMdrvEC= zMvYJ?nL$E?IU+izuC(c@0&twSI!SPrVKn=))TqM_&wfkKH7V@;au+!St#7s}R1 zmdU1siKCZ^X0WP`=y})FL8ARbpK%obSoavPrU?hC8-uTe1sw}Fb(X_jPLtAXlWwuM zXFfc2Ks2h@fam=Zadk=P~`al5pKhg4?ESTp#~hkvhlD4pn0W8@2Y{_ z{04b+vx%eJNzauC+1ZFBeCBNx!P>7KXpJFq=bwB1K8CyABv+XwT*^VX!s0Ag&hKp! zCFOg0qd#YedNgk!EU)Qc-Cb1`bK?k8-#(fZ+{AStb}3DT9tHdFaejZWN#&NBdUSl8 zo*sD;#63JR(lYa5FtG>S<|LRNV498+iE%ge;#s5BSRnxa_YjtNba|zcZ3C}}h=~2f z>$-*maQZGflnS(hvVevQl~hm&=NOP*JbiTZDDYRt#>NT9;k0{Czz6~J7!elMH~JWB z)xgc+pACc*45b>6V95$9l?pgz(CO>#)Go|xq^rS|(RF}DV%<*h{(rDh)%!uCE{`yP z=M&6PU%x0gVo1cmlt{Q5HxRM0qm+6>S^rR`dFP^nsq)4RPnGo|nd z=+lX#qmb3(sAlIeHpyxGU}-qztov2DdxYe9o{&r5|Mfs1g+0CB=oC&iN zCds~vbxQ>fVWP1#{isu2QkoBJIBAwJ*gFCa%+EbeR6_v4@3<){Qt&MuKI`dnxT3_1 zXD)FTf7&j1W5ikA);HO|t=TGMP?D!(gw&>PnR{o|83T8>9Bj;69sP>SlpdGcweWh) zn@1}=m^t{XZm_%@0_)M%ANugtxOmOvJ069km{Jo1jZ(qqd`@SHZ2)9w66R3Ut^vvu$2E5$8uLMV_U8o_MK*5wb>(gwE1ksS}kRtS6>kL}<)=M}?UvI0cg78s}P8s=#FvLcJq-<)aXU7V!+GJ=K_=tt7T z#ZEG+B+sVr4<*hqhc-p4^t!tfG=FXz#6^!igP`l2r|H>;5zGtx_c>R=Fj!eMjL7xW zVx@J&JNCC!lXWuAICEF)UcL~NzXyS%3)2C-{ox8g+ zIxWY0FQz`&bepZUwOxD9<>-%T()DduZQB873XZ=ng5mvJzWG*F*Ixf9X~HWf$n8~P z`xa_s_bj#K`75+)9)NenUAuZ0hs9#ChI^NVjz@3v0z)YYZW~DAuM9f`2qL1QYD)|| zaKi4BLq-4@v~R#nDPch5!ykN_=Z=D_2l_XEQCG#uQJGg!K@!tXFeH(ZftPEF z95|)t0=Lo$v-cAd(M=++ASWgX1a4jb`vBDchHU)&b1US*&5~<)8CJPRI$0gs`17sj zm?a6bcbJ9KcoTeANfU^49A^ZT_(P;Oz%U(%71YjqU}W~yVat&Yf*g7xE4UyjZXMO- zgN>5sw)#^qM#JysNR$|8I{1{CYh?>(su_UuWASO~TEq$6POCg2#H-32P?+l3xa)D` z9Aly`J0ZPpxYKBJ@r4T>N#Lk=1Vc*~?A#T?aA!VYKt{e@BHXj4VHkx+zoO@Gk{O^E zYkTG>{um1SqNv|vgT63`4G0s?pclVmRJe9-V)m|`M^JoscHjeZqYF`lN>6)PL|ZJ#~7M>O$Mvy2XaKMBw11S_{I0b z)@0#2=tI!$X`^Dd+bU1N4h3Hv`w_pV9R&9-nK6`RWo{1JN=KSfA;YdSmQ|#; zDIVXE*6d_9bRu%R=+m-3#>lzAme<+L;ZS1JEiKJKUHI1h(Y;d0Zu>rnk3hkzEc zZ3pTl6}2N;G1w0&X)d+b0wmaq8U>a{KI>4YA^DkOD!cl9i|k+>-uqCJ!()-3!|ps; zv$tSevEE1dbpWmulIWZBDyFI|~W-<5dy7`Nzv8QwM)= zR96052k?(e6mZ4 zW|M;~CS%OHT-gTejPY~J?<+wrb4w7~s-N|lBX4XOdn$}m9To(f=N%%;tV%Rzi-rxV zT^#2IH;pO9XC=#BivD`dHTE?&d2Ll2;x1TNq%3O`a86o=msaWK_c`WhTkT?oXv-7I z7>yzm2_8Shj=JVAmSY2}T@UrBMb>qj7Ln0i3{4?_P`{Ary_c zUP+rBsOE#WgMwH<$AutI;vnAu4m&6)2vpK2(dnNJU>JQCk1VfmL_mRTZE5+_BTGX> zb3@=;xQ*=e4dRddX%-y@0{Hk%=82ePbo{-Z&Fb64XM1KdK7Nt<#p7Lv#JYsRJ=>xm zzYfr$Cur^)iEeC(ez?1boeQouoZVyz`-+oxHZF*x}~>m-iz%pwpuzZ;I1O z_<6>3J$C{n<>H4OnhW$3>{l!+#9qqFHTtUYu0f|6@Yz*wLH{MCok-ElQ-!_tY43MY zHCmNFw^_a^^`uAqCgTe2H~Z);eDacrb9PkqeSK$Q#Gr#H8t9VqacHNzQ){U2?8}}$ zw#fhFV=zgT9mF$*4!o$$JXzhKd;2FU&BJH5ni$G#OdMs$P?$g@zA&Y!PYCO!Z-7O) z?MYFrV>D0gBnjF7D+?wh+G)x~OQE=;<7ymqku zzzL)(s{DkKI+Y!SGl|W&l`jQeC|p_{RZ^*U)yiF=uLC2&WiT z(RbV_QZ|350Au}1F{*p;nVgNXA-(%qt76`1p@(G5pGhFY%2r~6(LVOftI%x`NgSWw zWfM@nN7I%vbe&?@A0iw}+i%fwe|z~&4;No)ojBiq#^*ra1M7xz%WvEFgsvaSRiG*o zNcXfHez>KAEncTrL40|AGMMrv?o@~-e3Z|z$ly>u0xM>_Xjss$2A%{zzZ z&dt~QTZfnsRIbwWVHUd{B9B-7eDX~bO*J9MuzxblGOg^Ugk6A;DG8%VqQ|y4XbR|v zwRSlNY}Ky`S!npQuVp)ANVU%2H}X`Nt@pBnx0y1=G?z9drFY)fCfy@awU|Fkwc0zV z?2Qi%Y8uJMo!O+$yeZjc^ck2f|3-G~-=X?0 zWtlC-TX+63m##4RR9J#=w~vrbt-SB4tMh7Qhp#^LDNa*J)(++`#n$L=6T%BZ0=?$; z#E;uYrfs2pXU_?~5o$dCgBMJ$s-bxYJg0dbvdrY60QyTM*1A|NuOxz`8_wF8`QnD$ z+q#P{hl?$?hCfh?Qk@zfV#rKfYiLp9!ch`$??nxiE0UGINQN9@IdFVgq0k17bqmI%yUtNvC<_G)3} Y`|v9LOSv0t(NuH}= Date: Tue, 10 Sep 2024 12:57:45 +0200 Subject: [PATCH 32/37] CH-32 Add option to directly access a database --- deployment-configuration/helm/templates/auto-database.yaml | 2 +- deployment-configuration/value-template.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/deployment-configuration/helm/templates/auto-database.yaml b/deployment-configuration/helm/templates/auto-database.yaml index 6ec31380d..a53ea6861 100644 --- a/deployment-configuration/helm/templates/auto-database.yaml +++ b/deployment-configuration/helm/templates/auto-database.yaml @@ -101,7 +101,7 @@ metadata: app: {{ .app.harness.deployment.name | quote }} {{ include "deploy_utils.labels" .root | indent 4 }} spec: - type: ClusterIP + type: {{-if .app.harness.database.expose }}LoadBalancer{{- else }}ClusterIP{{- end }} selector: app: {{ .app.harness.database.name | quote }} ports: diff --git a/deployment-configuration/value-template.yaml b/deployment-configuration/value-template.yaml index c04439a3b..222aa7f67 100644 --- a/deployment-configuration/value-template.yaml +++ b/deployment-configuration/value-template.yaml @@ -75,6 +75,8 @@ harness: pass: metacell # -- image ref for referencing images from the build, e.g. image_ref: myownpgimage image_ref: + # -- expose database to the public with ingress + expose: false # -- settings for mongo database (for type==mongo) mongo: image: mongo:5 From 0e282101a4d1b066ea74f51bfc72059e571dd132 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 10 Sep 2024 13:07:15 +0200 Subject: [PATCH 33/37] CH-32 Update Neo4j --- deployment-configuration/value-template.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment-configuration/value-template.yaml b/deployment-configuration/value-template.yaml index 222aa7f67..ff2814668 100644 --- a/deployment-configuration/value-template.yaml +++ b/deployment-configuration/value-template.yaml @@ -92,7 +92,7 @@ harness: port: 5432 # -- settings for neo4j database (for type==neo4j) neo4j: - image: neo4j:4.1.9 + image: neo4j:5 memory: size: 256M pagecache: From f334040bf6ff9b7ca291935f1650bf696c002c06 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 10 Sep 2024 13:07:27 +0200 Subject: [PATCH 34/37] CH-32 Add documentation --- docs/applications/databases.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/applications/databases.md b/docs/applications/databases.md index 89bd2868b..96498f6cd 100644 --- a/docs/applications/databases.md +++ b/docs/applications/databases.md @@ -35,6 +35,9 @@ harness: `image_ref`: Optional setting, used for referencing a base/static image from the build. The complete image name with tag will automagically being generated from the values.yaml file. This setting overrides the `image` setting specific for the database type (e.g. postgres/image). Note: the referenced image must be included as a build dependency in order to be built by the pipelines. +`expose`: This option allows you to expose the database port through a load balancer. +Do not use on production! + ### Specific database settings @@ -91,7 +94,24 @@ harness #### Neo4j -Not yet supported! +Defaults: +```yaml +harness + database: + neo4j: + dbms_security_auth_enabled: "false" + image: neo4j:5 + memory: + heap: { initial: 64M, max: 128M } + pagecache: { size: 64M } + size: 256M + ports: + - { name: http, port: 7474 } + - { name: bolt, port: 7687 } +``` + +Not that the default resource values are not optimized and increasing the default memory is recommended for production. +Mapping memory configuration with Kubernetes resource requests is also recommended. ## Programmatic API From 06f99f12ca329c1c49684dd2f0e59220f17d1f41 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 10 Sep 2024 14:15:19 +0200 Subject: [PATCH 35/37] CH-32 Fix --- deployment-configuration/helm/templates/auto-database.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment-configuration/helm/templates/auto-database.yaml b/deployment-configuration/helm/templates/auto-database.yaml index a53ea6861..2e0c15864 100644 --- a/deployment-configuration/helm/templates/auto-database.yaml +++ b/deployment-configuration/helm/templates/auto-database.yaml @@ -101,7 +101,7 @@ metadata: app: {{ .app.harness.deployment.name | quote }} {{ include "deploy_utils.labels" .root | indent 4 }} spec: - type: {{-if .app.harness.database.expose }}LoadBalancer{{- else }}ClusterIP{{- end }} + type: {{ if .app.harness.database.expose }}LoadBalancer{{ else }}ClusterIP{{ end }} selector: app: {{ .app.harness.database.name | quote }} ports: From 9f5130f78bb58a2cf4ac5be424a7413c8601b2b3 Mon Sep 17 00:00:00 2001 From: Filippo Ledda <46561561+filippomc@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:12:34 +0200 Subject: [PATCH 36/37] Update applications/neo4j/README.md Co-authored-by: Alex --- applications/neo4j/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/neo4j/README.md b/applications/neo4j/README.md index 49dadb607..cd46617d4 100644 --- a/applications/neo4j/README.md +++ b/applications/neo4j/README.md @@ -3,7 +3,7 @@ Enable this application to deploy a Neo4j server with the neo4j browser enabled. ## How to use -The browser will be enabled at neo4j.[DOMAIN]. +The neo4j browser will be enabled at neo4j.[DOMAIN]. ![Neo4j browser login](docs/browser-login.png) From fefad142c8c588d34689845cb537d7ff457dd867 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Wed, 11 Sep 2024 15:19:27 +0200 Subject: [PATCH 37/37] CH-32 Fix neo4j 5 config --- .../helm/templates/auto-database-neo4j.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/deployment-configuration/helm/templates/auto-database-neo4j.yaml b/deployment-configuration/helm/templates/auto-database-neo4j.yaml index bddbab24b..d56ca21e3 100644 --- a/deployment-configuration/helm/templates/auto-database-neo4j.yaml +++ b/deployment-configuration/helm/templates/auto-database-neo4j.yaml @@ -5,22 +5,22 @@ image: {{ .app.harness.database.neo4j.image }} {{- end }} env: - - name: NEO4J_dbms_directories_data + - name: NEO4J_server_directories_data value: /data/db/data - - name: NEO4J_dbms_directories_logs + - name: NEO4J_server_directories_logs value: /data/db/logs - - name: NEO4J_dbms_directories_metrics + - name: NEO4J_server_directories_metrics value: /data/db/metrics - - name: NEO4J_dbms_memory_size - value: {{ .app.harness.database.neo4j.memory.size }} - - name: NEO4J_dbms_memory_pagecache_size + - name: NEO4J_server_memory_pagecache_size value: {{ .app.harness.database.neo4j.memory.pagecache.size }} - - name: NEO4J_dbms_memory_heap_initial__size + - name: NEO4J_server_memory_heap_initial__size value: {{ .app.harness.database.neo4j.memory.heap.initial }} - - name: NEO4J_dbms_memory_heap_max__size + - name: NEO4J_server_memory_heap_max__size value: {{ .app.harness.database.neo4j.memory.heap.max }} - name: NEO4J_dbms_security_auth__enabled value: {{ .app.harness.database.neo4j.dbms_security_auth_enabled | quote }} - name: NEO4J_auth value: {{ .app.harness.database.user }}/{{ .app.harness.database.pass }} + - name: NEO4J_server_config_strict__validation_enabled + value: "false" {{- end }} \ No newline at end of file