def main(): # Fetching and loading Kubernetes Information config.load_kube_config() # For incluster details # config.load_incluster_config() extensions_v1_beta1 = client.ExtensionsV1beta1Api() body = client.ExtensionsV1beta1Ingress( api_version="networking.k8s.io/v1beta1", kind="Ingress", metadata=client.V1ObjectMeta( name="ingress-example", annotations={"nginx.ingress.kubernetes.io/rewrite-target": "/"}), spec=client.ExtensionsV1beta1IngressSpec(rules=[ client.ExtensionsV1beta1IngressRule( host="abc.xyz.com", http=client.ExtensionsV1beta1HTTPIngressRuleValue( paths=list[client.ExtensionsV1beta1HTTPIngressPath( path="/api", backend=client.ExtensionsV1beta1IngressBackend( service_name="ingress", service_port=5000))])) ])) # Can specify a namespace that you have created extensions_v1_beta1.create_namespaced_ingress(namespace="default", body=body)
def build_ingress(services, dns_suffix, dual_dns_prefix_annotation_name, ingress_info): ingress = client.ExtensionsV1beta1Ingress() # init metadata ingress.metadata = client.V1ObjectMeta() ingress.metadata.name = ingress_info["ingress_name"] # init spec ingress.spec = client.ExtensionsV1beta1IngressSpec() ingress.spec.rules = [] service_tuples = _create_ingress_service_tuples( services, dual_dns_prefix_annotation_name) for dns_prefix, port, service in service_tuples: ingress_rule = client.ExtensionsV1beta1IngressRule() ingress_rule.host = "%s.%s" % (dns_prefix, dns_suffix) backend = client.ExtensionsV1beta1IngressBackend( service_name=service.metadata.name, service_port=port) ingress_path = [ client.ExtensionsV1beta1HTTPIngressPath(path="/", backend=backend) ] ingress_rule.http = client.ExtensionsV1beta1HTTPIngressRuleValue( ingress_path) ingress.spec.rules.append(ingress_rule) if not ingress.spec.rules: ingress_dummy_backend = client.ExtensionsV1beta1IngressBackend( service_name=ingress_info["ingress_controller_service_name"], service_port=80) ingress.spec.backend = ingress_dummy_backend return ingress
def generate_ingress(ingress_name: str): metadata = client.V1ObjectMeta( name=ingress_name, namespace="production", labels={"certmanager-solver": "nginx-platform-production"}, annotations={ "kubernetes.io/ingress.class": "nginx-platform-production", "kubernetes.io/tls-acme": "true", "meta.helm.sh/release-name": "platform-ingress", "meta.helm.sh/release-namespace": "production", "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod", "nginx.ingress.kubernetes.io/ssl-redirect": "true", "nginx.ingress.kubernetes.io/proxy-body-size": "0", "nginx.ingress.kubernetes.io/server-snippet": "location = /check-dns {\n return 200;\n}", "nginx.ingress.kubernetes.io/configuration-snippet": 'proxy_set_header Host $host;\nproxy_set_header whitelabel "$host";', }, ) spec = client.ExtensionsV1beta1IngressSpec( rules=[ client.ExtensionsV1beta1IngressRule( host=ingress_name, http=client.ExtensionsV1beta1HTTPIngressRuleValue(paths=[ client.ExtensionsV1beta1HTTPIngressPath( path="/", backend=client.ExtensionsV1beta1IngressBackend( service_name="platform-app", service_port=3000), ) ]), ) ], tls=[ client.ExtensionsV1beta1IngressTLS(hosts=[ingress_name], secret_name=ingress_name + "-tls") ], ) return client.ExtensionsV1beta1Ingress(kind="Ingress", api_version="extensions/v1beta1", metadata=metadata, spec=spec)
def simple_ingress(): """Return the Kubernetes config matching the simple-ingress.yaml manifest.""" return client.ExtensionsV1beta1Ingress( api_version='extensions/v1beta1', kind='Ingress', metadata=client.V1ObjectMeta(name='my-ingress'), spec=client.ExtensionsV1beta1IngressSpec(rules=[ client.ExtensionsV1beta1IngressRule( http=client.ExtensionsV1beta1HTTPIngressRuleValue(paths=[ client.ExtensionsV1beta1HTTPIngressPath( backend=client.ExtensionsV1beta1IngressBackend( service_name='my-service', service_port=80), path='/') ])) ], ))
def create_ingress(extensions_v1_beta1): body = client.ExtensionsV1beta1Ingress( api_version="networking.k8s.io/v1beta1", kind="Ingress", metadata=client.V1ObjectMeta( name="ingress-example", annotations={"nginx.ingress.kubernetes.io/rewrite-target": "/"}), spec=client.ExtensionsV1beta1IngressSpec(rules=[ client.ExtensionsV1beta1IngressRule( host="boddulabs.com", http=client.ExtensionsV1beta1HTTPIngressRuleValue(paths=[ client.ExtensionsV1beta1HTTPIngressPath( path="/", backend=client.ExtensionsV1beta1IngressBackend( service_port=5678, service_name="service-example")) ])) ])) # Creation of the Deployment in specified namespace # (Can replace "default" with a namespace you may have created) extensions_v1_beta1.create_namespaced_ingress(namespace="default", body=body)
def create_deployment_ingress(deployment: k8s.V1Deployment) -> None: """Create an ingress to a service backed by a deployment. :param deployment: A configured deployment object. """ namespace = deployment.metadata.namespace name = deployment.metadata.name pod_port = int(deployment.metadata.annotations["port"]) ingress_path = f"{ingress_route(namespace, name)}(/|$)(.*)" ingress_spec = k8s.ExtensionsV1beta1IngressSpec(rules=[ k8s.ExtensionsV1beta1IngressRule( http=k8s.ExtensionsV1beta1HTTPIngressRuleValue(paths=[ k8s.ExtensionsV1beta1HTTPIngressPath( path=ingress_path, backend=k8s.ExtensionsV1beta1IngressBackend( service_name=name, service_port=pod_port), ) ])) ]) ingress_metadata = k8s.V1ObjectMeta( namespace=namespace, name=name, annotations={ "kubernetes.io/ingress.class": "nginx", "nginx.ingress.kubernetes.io/rewrite-target": "/$2", }, labels={ "app": "bodywork", "stage": name }, ) ingress = k8s.ExtensionsV1beta1Ingress(metadata=ingress_metadata, spec=ingress_spec) k8s.ExtensionsV1beta1Api().create_namespaced_ingress(namespace=namespace, body=ingress)
def post(self): """ """ current_user_id = get_jwt_identity() current_user_roles = get_jwt_claims()['roles'] project_schema = ProjectSchema() project_data = request.get_json() validated_project_data, errors = project_schema.load(project_data) if errors: return dict(status='fail', message=errors), 400 if not has_role(current_user_roles, 'administrator'): validated_project_data['owner_id'] = current_user_id # check if project already exists existing_project = Project.find_first( name=validated_project_data['name'], owner_id=validated_project_data['owner_id']) if existing_project: return dict( status='fail', message= f'project with name {validated_project_data["name"]} already exists' ), 409 try: validated_project_data['alias'] =\ create_alias(validated_project_data['name']) namespace_name = validated_project_data['alias'] cluster_id = validated_project_data['cluster_id'] cluster = Cluster.get_by_id(cluster_id) if not cluster: return dict(status='fail', message=f'cluster {cluster_id} not found'), 404 kube_host = cluster.host kube_token = cluster.token kube_client = create_kube_clients(kube_host, kube_token) # create namespace in cluster cluster_namespace = kube_client.kube.create_namespace( client.V1Namespace(metadata=client.V1ObjectMeta( name=namespace_name))) # create project in database if cluster_namespace: ingress_name = f"{validated_project_data['alias']}-ingress" ingress_meta = client.V1ObjectMeta(name=ingress_name) ingress_default_rule = client.ExtensionsV1beta1IngressRule( host="traefik-ui.cranecloud.io", http=client.ExtensionsV1beta1HTTPIngressRuleValue(paths=[ client.ExtensionsV1beta1HTTPIngressPath( path="/*", backend=client.ExtensionsV1beta1IngressBackend( service_name="traefik-web-ui-ext", service_port=80)) ])) ingress_spec = client.ExtensionsV1beta1IngressSpec( rules=[ingress_default_rule]) ingress_body = client.ExtensionsV1beta1Ingress( metadata=ingress_meta, spec=ingress_spec) kube_client.extension_api.create_namespaced_ingress( namespace=namespace_name, body=ingress_body) project = Project(**validated_project_data) saved = project.save() if not saved: # delete the namespace kube_client.kube.delete_namespace(namespace_name) return dict(status='fail', message='Internal Server Error'), 500 new_project_data, errors = project_schema.dump(project) return dict(status='success', data=dict(project=new_project_data)), 201 except client.rest.ApiException as e: return dict(status='fail', message=e.body), e.status except Exception as err: return dict(status='fail', message=str(err)), 500
def get_user_vnc_pod(uuid, user): extension_api = ExtensionsV1beta1Api(get_kubernetes_api_client()) app_api = AppsV1Api(get_kubernetes_api_client()) core_api = CoreV1Api(get_kubernetes_api_client()) result = {} has_deployment = False user_vnc = None try: setting = TaskSettings.objects.get(uuid=uuid) user_vnc, _ = TaskVNCPod.objects.get_or_create( settings=setting, user=user, defaults={ 'settings': setting, 'user': user, 'pod_name': '', 'url_path': '', 'vnc_password': '', 'expire_time': round(time.time() + USER_SPACE_POD_TIMEOUT) }) _, created = TaskStorage.objects.get_or_create(settings=setting, user=user, defaults={ 'settings': setting, 'user': user, 'pod_name': '' }) if user_vnc.pod_name: try: # check whether deployment is on has_deployment = True _ = app_api.read_namespaced_deployment( name=user_vnc.pod_name, namespace=KUBERNETES_NAMESPACE) except ApiException as ex: if ex.status != 404: LOGGER.exception(ex) else: has_deployment = False selector = "task-{}-user-{}-vnc".format(setting.uuid, user.id) if not has_deployment: # create a new deployment conf = json.loads(setting.container_config) user_dir = "user_{}_task_{}".format(user.id, setting.id) dep_name = "task-vnc-{}-{}".format(setting.uuid, get_short_uuid()) shared_pvc_name = "shared-{}".format(setting.uuid) shared_mount = client.V1VolumeMount( mount_path=conf['persistent_volume']['mount_path'], name=shared_pvc_name, read_only=True) user_storage_name = "user-{}".format(setting.uuid) user_mount = client.V1VolumeMount( mount_path='/cloud_scheduler_userspace', name=user_storage_name, sub_path=user_dir) username = '******'.format(user.username, setting.id) commands = [ 'set +e', 'ln -s /cloud_scheduler_userspace /headless/Desktop/user_space', 'useradd -u {uid} {username}'.format(uid=499 + user.id, username=username), 'usermod -d /headless {}'.format(username), "su -s /bin/bash -c '/dockerstartup/vnc_startup.sh -w' {}". format(username) ] if created: cp_command = 'cp -r {}/* /headless/Desktop/user_space'.format( conf['persistent_volume']['mount_path'] + '/' + conf['task_initial_file_path']) chown = 'chown -R {user}:{user} /headless/Desktop/user_space/*'.format( user=username) commands.insert(4, cp_command) commands.insert(5, chown) vnc_pw = random_password(8) env_vnc_pw = client.V1EnvVar(name="VNC_PW", value=vnc_pw) container = client.V1Container( name='headless-vnc', image=config.USER_VNC_DOCKER_IMAGE, env=[env_vnc_pw], command=['/bin/bash'], args=['-c', ';'.join(commands)], volume_mounts=[shared_mount, user_mount]) persistent_volume_claim = client.V1PersistentVolumeClaimVolumeSource( claim_name=conf['persistent_volume']['name']) user_volume_claim = client.V1PersistentVolumeClaimVolumeSource( claim_name=USERSPACE_NAME) shared_volume = client.V1Volume( name=shared_pvc_name, persistent_volume_claim=persistent_volume_claim) user_volume = client.V1Volume( name=user_storage_name, persistent_volume_claim=user_volume_claim) template = client.V1PodTemplateSpec( metadata=client.V1ObjectMeta(labels={'app': selector}), spec=client.V1PodSpec(containers=[container], volumes=[shared_volume, user_volume])) spec = client.V1DeploymentSpec( replicas=1, template=template, selector={'matchLabels': { 'app': selector }}) deployment = client.V1Deployment( kind='Deployment', metadata=client.V1ObjectMeta( name=dep_name, namespace=KUBERNETES_NAMESPACE, labels={'app': selector}), spec=spec) app_api.create_namespaced_deployment( body=deployment, namespace=KUBERNETES_NAMESPACE) user_vnc.pod_name = dep_name user_vnc.vnc_password = vnc_pw if not user_vnc.url_path: # create service spec = client.V1ServiceSpec( external_name=selector, ports=[ client.V1ServicePort(name='websocket-port', port=config.USER_VNC_PORT, target_port=config.USER_VNC_PORT) ], selector={'app': selector}, type='ClusterIP', ) service = client.V1Service(spec=spec, metadata=client.V1ObjectMeta( labels={'app': selector}, name=selector, namespace=KUBERNETES_NAMESPACE)) try: core_api.create_namespaced_service( namespace=KUBERNETES_NAMESPACE, body=service) except ApiException as ex: if ex.status != 409: # ignore conflict (duplicate) LOGGER.exception(ex) raise ApiException # create ingress url_path = str(get_uuid()) spec = client.ExtensionsV1beta1IngressSpec( rules=[ client.ExtensionsV1beta1IngressRule( host=config.USER_VNC_HOST, http=client.ExtensionsV1beta1HTTPIngressRuleValue( paths=[ client.ExtensionsV1beta1HTTPIngressPath( client.ExtensionsV1beta1IngressBackend( service_name=selector, service_port=config.USER_VNC_PORT), path='/' + url_path) ])) ], tls=[ client.ExtensionsV1beta1IngressTLS( hosts=[config.USER_VNC_HOST], secret_name=config.USER_VNC_TLS_SECRET) ], ) ingress = client.ExtensionsV1beta1Ingress(metadata={ 'name': selector, 'annotations': { 'kubernetes.io/ingress.class': 'nginx', 'nginx.ingress.kubernetes.io/proxy-read-timeout': '86400', 'nginx.ingress.kubernetes.io/proxy-send-timeout': '86400', } }, spec=spec) need_patch = False try: extension_api.create_namespaced_ingress( KUBERNETES_NAMESPACE, ingress) except ApiException as ex: if ex.status != 409: # ignore conflict (duplicate) LOGGER.exception(ex) raise ApiException else: need_patch = True if need_patch: extension_api.patch_namespaced_ingress( selector, KUBERNETES_NAMESPACE, ingress) user_vnc.url_path = url_path user_vnc.expire_time = round(time.time() + USER_SPACE_POD_TIMEOUT) result['url_path'] = user_vnc.url_path result['vnc_password'] = user_vnc.vnc_password result['deployment_name'] = user_vnc.pod_name result['vnc_host'] = config.USER_VNC_HOST result['vnc_port'] = config.USER_VNC_WS_PORT user_vnc.save(force_update=True) except ApiException as ex: LOGGER.exception(ex) except Exception as ex: LOGGER.exception(ex) finally: if user_vnc: user_vnc.save(force_update=True) return result
def on_spawn(self, task): ports = [] rules = [] idx = 0 for path, route in task.routes.items(): port = route['port'] idx += 1 port_name = f'route{idx}' ports.append( client.V1ServicePort( name=port_name, port=port, target_port=port, )) rules.append( client.ExtensionsV1beta1IngressRule( host=f'{task.id}.{self.cluster.domain}', http=client.ExtensionsV1beta1HTTPIngressRuleValue(paths=[ client.ExtensionsV1beta1HTTPIngressPath( path=path, backend=client.ExtensionsV1beta1IngressBackend( service_name=task.id, service_port=port_name, ), ), ], ), )) if len(rules) == 0: return print('~~ creating task ingress', path, '-> port', port) self.cluster.core.create_namespaced_service( namespace=self.cluster.namespace, body=client.V1Service( metadata=client.V1ObjectMeta( name=task.id, namespace=self.cluster.namespace, labels={ LABEL_TASK_ID: task.id, }, ), spec=client.V1ServiceSpec( selector={ LABEL_TASK_ID: task.id, }, ports=ports, ), ), ) self.cluster.ext.create_namespaced_ingress( namespace=self.cluster.namespace, body=client.ExtensionsV1beta1Ingress( metadata=client.V1ObjectMeta( name=task.id, labels={ LABEL_TASK_ID: task.id, }, annotations={ 'kubernetes.io/ingress.class': 'traefik', 'traefik.frontend.rule.type': 'PathPrefix', }, ), spec=client.ExtensionsV1beta1IngressSpec(rules=rules, ), ), )
def post(self, project_id): """ """ resource_registry = { 'db_deployment': False, 'db_service': False, 'image_pull_secret': False, 'app_deployment': False, 'app_service': False, 'ingress_entry': False } current_user_id = get_jwt_identity() current_user_roles = get_jwt_claims()['roles'] app_schema = AppSchema() app_data = request.get_json() validated_app_data, errors = app_schema.load(app_data, partial=("project_id", )) if errors: return dict(status='fail', message=errors), 400 existing_app = App.find_first(name=validated_app_data['name'], project_id=project_id) if existing_app: return dict( status='fail', message= f'App with name {validated_app_data["name"]} already exists' ), 409 validated_app_data['port'] = validated_app_data.get('port', 80) app_name = validated_app_data['name'] app_alias = create_alias(validated_app_data['name']) app_image = validated_app_data['image'] command = validated_app_data.get('command', None) # env_vars = validated_app_data['env_vars'] env_vars = validated_app_data.get('env_vars', None) private_repo = validated_app_data.get('private_image', False) docker_server = validated_app_data.get('docker_server', None) docker_username = validated_app_data.get('docker_username', None) docker_password = validated_app_data.get('docker_password', None) docker_email = validated_app_data.get('docker_email', None) replicas = validated_app_data.get('replicas', 1) app_port = validated_app_data.get('port', None) image_pull_secret = None command = command.split() if command else None project = Project.get_by_id(project_id) if not project: return dict(status='fail', message=f'project {project_id} not found'), 404 if not is_owner_or_admin(project, current_user_id, current_user_roles): return dict(status='fail', message='Unauthorised'), 403 cluster = project.cluster namespace = project.alias if not cluster: return dict(status='fail', message="Invalid Cluster"), 500 # check if app already exists app = App.find_first(**{'name': app_name}) if app: return dict(status='fail', message=f'App {app_name} already exists'), 409 kube_host = cluster.host kube_token = cluster.token service_host = urlsplit(kube_host).hostname kube_client = create_kube_clients(kube_host, kube_token) try: # create the app new_app = App(name=app_name, image=app_image, project_id=project_id, alias=app_alias, port=app_port) if private_repo: # handle gcr credentials if 'gcr' in docker_server and docker_username == '_json_key': docker_password = json.dumps( json.loads(base64.b64decode(docker_password))) # create image pull secrets authstring = base64.b64encode( f'{docker_username}:{docker_password}'.encode("utf-8")) secret_dict = dict( auths={ docker_server: { "username": docker_username, "password": docker_password, "email": docker_email, "auth": str(authstring, "utf-8") } }) secret_b64 = base64.b64encode( json.dumps(secret_dict).encode("utf-8")) secret_body = client.V1Secret( metadata=client.V1ObjectMeta(name=app_alias), type='kubernetes.io/dockerconfigjson', data={'.dockerconfigjson': str(secret_b64, "utf-8")}) kube_client.kube.create_namespaced_secret( namespace=namespace, body=secret_body, _preload_content=False) # update registry resource_registry['image_pull_secret'] = True image_pull_secret = client.V1LocalObjectReference( name=app_alias) # create app deployment's pvc meta and spec # pvc_name = f'{app_alias}-pvc' # pvc_meta = client.V1ObjectMeta(name=pvc_name) # access_modes = ['ReadWriteOnce'] # storage_class = 'openebs-standard' # resources = client.V1ResourceRequirements( # requests=dict(storage='1Gi')) # pvc_spec = client.V1PersistentVolumeClaimSpec( # access_modes=access_modes, resources=resources, storage_class_name=storage_class) # Create a PVC # pvc = client.V1PersistentVolumeClaim( # api_version="v1", # kind="PersistentVolumeClaim", # metadata=pvc_meta, # spec=pvc_spec # ) # kube_client.kube.create_namespaced_persistent_volume_claim( # namespace=namespace, # body=pvc # ) # create deployment dep_name = f'{app_alias}-deployment' # # EnvVar env = [] if env_vars: for key, value in env_vars.items(): env.append(client.V1EnvVar(name=str(key), value=str(value))) # pod template container = client.V1Container( name=app_alias, image=app_image, ports=[client.V1ContainerPort(container_port=app_port)], env=env, command=command # volume_mounts=[client.V1VolumeMount(mount_path="/data", name=dep_name)] ) #pod volumes # volumes = client.V1Volume( # name=dep_name # # persistent_volume_claim=client.V1PersistentVolumeClaimVolumeSource(claim_name=pvc_name) # ) # spec template = client.V1PodTemplateSpec( metadata=client.V1ObjectMeta(labels={'app': app_alias}), spec=client.V1PodSpec(containers=[container], image_pull_secrets=[image_pull_secret] # volumes=[volumes] )) # spec of deployment spec = client.V1DeploymentSpec( replicas=replicas, template=template, selector={'matchLabels': { 'app': app_alias }}) # Instantiate the deployment deployment = client.V1Deployment( api_version="apps/v1", kind="Deployment", metadata=client.V1ObjectMeta(name=dep_name), spec=spec) # create deployment in cluster kube_client.appsv1_api.create_namespaced_deployment( body=deployment, namespace=namespace, _preload_content=False) # update registry resource_registry['app_deployment'] = True # create service in the cluster service_name = f'{app_alias}-service' service_meta = client.V1ObjectMeta(name=service_name, labels={'app': app_alias}) service_spec = client.V1ServiceSpec( type='ClusterIP', ports=[client.V1ServicePort(port=3000, target_port=app_port)], selector={'app': app_alias}) service = client.V1Service(metadata=service_meta, spec=service_spec) kube_client.kube.create_namespaced_service(namespace=namespace, body=service, _preload_content=False) # update resource registry resource_registry['app_service'] = True # subdomain for the app # sub_domain = f'{app_alias}.cranecloud.io' sub_domain = get_app_subdomain(app_alias) # create new ingres rule for the application new_ingress_backend = client.ExtensionsV1beta1IngressBackend( service_name=service_name, service_port=3000) new_ingress_rule = client.ExtensionsV1beta1IngressRule( host=sub_domain, http=client.ExtensionsV1beta1HTTPIngressRuleValue(paths=[ client.ExtensionsV1beta1HTTPIngressPath( path="", backend=new_ingress_backend) ])) ingress_name = f'{project.alias}-ingress' # Check if there is an ingress resource in the namespace, create if not ingress_list = kube_client.extension_api.list_namespaced_ingress( namespace=namespace).items if not ingress_list: ingress_meta = client.V1ObjectMeta(name=ingress_name) ingress_spec = client.ExtensionsV1beta1IngressSpec( # backend=ingress_backend, rules=[new_ingress_rule]) ingress_body = client.ExtensionsV1beta1Ingress( metadata=ingress_meta, spec=ingress_spec) kube_client.extension_api.create_namespaced_ingress( namespace=namespace, body=ingress_body) # update registry resource_registry['ingress_entry'] = True else: # Update ingress with new entry ingress = ingress_list[0] ingress.spec.rules.append(new_ingress_rule) kube_client.extension_api.patch_namespaced_ingress( name=ingress_name, namespace=namespace, body=ingress) service_url = f'https://{sub_domain}' new_app.url = service_url saved = new_app.save() if not saved: return dict(status='fail', message='Internal Server Error'), 500 new_app_data, _ = app_schema.dump(new_app) return dict(status='success', data=dict(app=new_app_data)), 201 except client.rest.ApiException as e: resource_clean_up(resource_registry, app_alias, namespace, kube_client) return dict(status='fail', message=json.loads(e.body)), 500 except Exception as e: resource_clean_up(resource_registry, app_alias, namespace, kube_client) return dict(status='fail', message=str(e)), 500
def userpod(pod_type, username, eppn, uid, ugid, groupname, ggid, annotations={}): """Starts a user pod Parameters ---------- pod_type: str The workload type of the pod to launch, e.g. "theia-python" username: str The short username for the user, e.g. "mst3k" eppn: str The eppn / long username, e.g. "*****@*****.**" uid: int The numeric user ID of the user that the pod will run as ugid: int The numeric GID of the user's primary group groupname: str Opaque group name for project mount ggid: int The numeric group ID the pod will run as annotations: dict Any additional annotations for the ingress Returns ------- pod_dns: str The partly-random domain name of the pos; can be used to check the pod's status, and determines the URL: https://<pod_dns> """ cfg = get_config() v1 = client.CoreV1Api() v1beta = client.ExtensionsV1beta1Api() namespace = cfg["NAMESPACE"] type_maps = v1.list_namespaced_config_map(namespace, label_selector="class=userpod") ntypes = len(type_maps.items) podcfg = None for i in range(ntypes): if type_maps.items[i].metadata.name == pod_type: podcfg = type_maps.items[i] break if not podcfg: raise Exception("Unsupported type") poddata = podcfg.data passwd = poddata["passwd"] passwd = passwd.replace("<UID>", str(uid)) passwd = passwd.replace("<UGID>", str(ugid)) group = poddata["group"] group = group.replace("<UGID>", str(ugid)) group = group.replace("<PGID>", str(ggid)) pod_port = poddata["port"] envoycfg = cfg["ENVOY_TEMPLATE"] envoyext = cfg["ENVOY_EXTERNAL"] envoyadm = cfg["ENVOY_ADMIN"] envoycfg = envoycfg.replace("<SERVICEPORT>", pod_port) envoycfg = envoycfg.replace("<ENVOYADMIN>", envoyadm) envoycfg = envoycfg.replace("<ENVOYEXTERNAL>", envoyext) envoycfg = envoycfg.replace("<SHORTUSER>", username) envoycfg = envoycfg.replace("<LONGUSER>", eppn) podmap = { "passwd": passwd, "group": group, "envoy": envoycfg, } username_label = gen_user_label(username) dashed_username = username.replace("@", "-") dashed_username = dashed_username.replace(".", "-") cfgmap = client.V1ConfigMap( api_version="v1", kind="ConfigMap", metadata=client.V1ObjectMeta( generate_name="%s-%s-" % (pod_type, dashed_username), labels={ "username-label": username_label, }, ), data=podmap, ) created_map = v1.create_namespaced_config_map(namespace, cfgmap) pod_name = created_map.metadata.name patch_labels = { "user-pod": pod_name, } label = { "metadata": { "labels": patch_labels, }, } v1.patch_namespaced_config_map(pod_name, namespace=namespace, body=label) resource_labels = { "username-label": username_label, "user-pod": pod_name, } pod_volumes = [ client.V1Volume(name="cfgfiles", config_map=client.V1ConfigMapVolumeSource( name=pod_name, )), ] userpod_mounts = [ client.V1VolumeMount( name="cfgfiles", mount_path="/etc/passwd", sub_path="passwd", ), client.V1VolumeMount( name="cfgfiles", mount_path="/etc/group", sub_path="group", ), ] if "HOME_PREFIX" in cfg: # NOTE / TODO: This will change eventually pod_volumes.append( client.V1Volume(name="home", host_path=client.V1HostPathVolumeSource( path="%s/%s" % (cfg["HOME_PREFIX"], username), type="Directory"))) userpod_mounts.append( client.V1VolumeMount(name="home", mount_path="/home/user")) if "PROJECT_PREFIX" in cfg: pod_volumes.append( client.V1Volume( name="project", host_path=client.V1HostPathVolumeSource( path="%s/%s" % (cfg["PROJECT_PREFIX"], groupname), type="Directory"))) userpod_mounts.append( client.V1VolumeMount(name="project", mount_path="/home/project")) registry = cfg["REGISTRY"] reg_org = cfg["REGISTRY_ORG"] envoy = cfg["ENVOY_CONTAINER"] supplemental = [] if ugid != ggid: supplemental = [ggid] pod = client.V1Pod(api_version="v1", kind="Pod", metadata=client.V1ObjectMeta( name=pod_name, labels=resource_labels, ), spec=client.V1PodSpec( volumes=pod_volumes, restart_policy="OnFailure", security_context=client.V1PodSecurityContext( supplemental_groups=supplemental), containers=[ client.V1Container( name=pod_type, image="%s/%s/%s:latest" % (registry, reg_org, pod_type), security_context=client.V1SecurityContext( run_as_user=uid, run_as_group=ugid, ), volume_mounts=userpod_mounts, ), client.V1Container( name="envoy", image=envoy, volume_mounts=[ client.V1VolumeMount( name="cfgfiles", mount_path="/etc/envoy/envoy.yaml", sub_path="envoy", ), ], ), ], )) v1.create_namespaced_pod(namespace=namespace, body=pod) service = client.V1Service(api_version="v1", kind="Service", metadata=client.V1ObjectMeta( name=pod_name, labels=resource_labels, namespace=namespace, ), spec=client.V1ServiceSpec( selector=resource_labels, ports=[ client.V1ServicePort( port=80, protocol="TCP", target_port=int(envoyext), ) ])) v1.create_namespaced_service(namespace, body=service) env_service = client.V1Service(api_version="v1", kind="Service", metadata=client.V1ObjectMeta( name="%s-envoy" % pod_name, labels=resource_labels, namespace=namespace, ), spec=client.V1ServiceSpec( selector=resource_labels, ports=[ client.V1ServicePort( port=9000, protocol="TCP", target_port=int(envoyadm), ) ])) v1.create_namespaced_service(namespace, body=env_service) pod_dom = cfg["POD_DOMAIN"] pod_dns = "%s.%s" % (pod_name, pod_dom) annotations["kubernetes.io/ingress.class"] = "nginx" ingress = client.ExtensionsV1beta1Ingress( metadata=client.V1ObjectMeta( name=pod_name, labels=resource_labels, namespace=namespace, annotations=annotations, ), spec=client.ExtensionsV1beta1IngressSpec(rules=[ client.ExtensionsV1beta1IngressRule( host=pod_dns, http=client.ExtensionsV1beta1HTTPIngressRuleValue(paths=[ client.ExtensionsV1beta1HTTPIngressPath( path="/", backend=client.ExtensionsV1beta1IngressBackend( service_name=pod_name, service_port=80, ), ) ], ), ) ], ), ) v1beta.create_namespaced_ingress(namespace, body=ingress) return pod_dns