def make_service( name, port, labels=None, annotations=None, ): """ Make a k8s service specification for fronting the pod running a user notebook. Parameters ---------- name: Name of the service. Must be a valid DNS label. port: The port to which the service binds. labels: Labels to add to the spawned service. annotations: Annotations to add to the spawned service. """ return V1Service( kind='Service', metadata=V1ObjectMeta(name=name, labels=labels, annotations=annotations), spec=V1ServiceSpec( type='ClusterIP', selector={'hub.jupyter.org/server-name': name}, ports=[V1ServicePort(port=port, target_port=port)] ) )
def make_ingress(name, routespec, target, data): """ Returns an ingress, service, endpoint object that'll work for this service """ meta = V1ObjectMeta(name=name, annotations={ 'hub.jupyter.org/proxy-data': json.dumps(data), 'hub.jupyter.org/proxy-routespec': routespec, 'hub.jupyter.org/proxy-target': target }, labels={ 'heritage': 'jupyterhub', 'component': 'singleuser-server', 'hub.jupyter.org/proxy-route': 'true' }) if routespec.startswith('/'): host = None path = routespec else: host, path = routespec.split('/', 1) target_parts = urlparse(target) target_ip = target_parts.hostname target_port = target_parts.port # Make endpoint object endpoint = V1Endpoints(kind='Endpoints', metadata=meta, subsets=[ V1EndpointSubset( addresses=[V1EndpointAddress(ip=target_ip)], ports=[V1EndpointPort(port=target_port)]) ]) # Make service object service = V1Service( kind='Service', metadata=meta, spec=V1ServiceSpec( ports=[V1ServicePort(port=target_port, target_port=target_port)])) # Make Ingress object ingress = V1beta1Ingress( kind='Ingress', metadata=meta, spec=V1beta1IngressSpec(rules=[ V1beta1IngressRule(host=host, http=V1beta1HTTPIngressRuleValue(paths=[ V1beta1HTTPIngressPath( path=path, backend=V1beta1IngressBackend( service_name=name, service_port=target_port)) ])) ])) return endpoint, service, ingress
def test_get_app_service_node_port(mocker): test_node_port = 1234 get_app_services_mock = mocker.patch('util.k8s.k8s_info.get_app_services') get_app_services_mock.return_value = [ V1Service(spec=V1ServiceSpec(ports=[ V1ServicePort(node_port=test_node_port, port=test_node_port) ])) ] assert get_app_service_node_port( NAUTAAppNames.DOCKER_REGISTRY) == test_node_port
async def aw(): await fw.add(V1Service(metadata=V1ObjectMeta(name="rejected"))) await fw.delete(V1Pod(metadata=V1ObjectMeta(name="foo"))) await fw.modify( V1Pod(metadata=V1ObjectMeta(name="bar", resource_version="55")) ) await fw.add( V1Pod(metadata=V1ObjectMeta(name="baz", resource_version="32")) ) await fw.stop()
def make_service( name, port, servername, owner_references, labels=None, annotations=None, ): """ Make a k8s service specification for using dns to communicate with the notebook. Parameters ---------- name: Name of the service. Must be unique within the namespace the object is going to be created in. env: Dictionary of environment variables. labels: Labels to add to the service. annotations: Annotations to add to the service. """ metadata = V1ObjectMeta( name=name, annotations=(annotations or {}).copy(), labels=(labels or {}).copy(), owner_references=owner_references, ) service = V1Service( kind='Service', metadata=metadata, spec=V1ServiceSpec( type='ClusterIP', ports=[V1ServicePort(port=port, target_port=port)], selector={ 'component': 'singleuser-server', 'hub.jupyter.org/servername': servername, 'hub.jupyter.org/username': metadata.labels['hub.jupyter.org/username'], }, ), ) return service
def make_ingress(name, routespec, target, labels, data): """ Returns an ingress, service, endpoint object that'll work for this service """ # move beta imports here, # which are more sensitive to kubernetes version # and will change when they move out of beta # because of the API changes in 1.16, the import is tried conditionally # to keep compatibility with older K8S versions try: from kubernetes.client.models import ( ExtensionsV1beta1Ingress, ExtensionsV1beta1IngressSpec, ExtensionsV1beta1IngressRule, ExtensionsV1beta1HTTPIngressRuleValue, ExtensionsV1beta1HTTPIngressPath, ExtensionsV1beta1IngressBackend, ) except ImportError: from kubernetes.client.models import ( V1beta1Ingress as ExtensionsV1beta1Ingress, V1beta1IngressSpec as ExtensionsV1beta1IngressSpec, V1beta1IngressRule as ExtensionsV1beta1IngressRule, V1beta1HTTPIngressRuleValue as ExtensionsV1beta1HTTPIngressRuleValue, V1beta1HTTPIngressPath as ExtensionsV1beta1HTTPIngressPath, V1beta1IngressBackend as ExtensionsV1beta1IngressBackend) meta = V1ObjectMeta( name=name, annotations={ 'hub.jupyter.org/proxy-data': json.dumps(data), 'hub.jupyter.org/proxy-routespec': routespec, 'hub.jupyter.org/proxy-target': target }, labels=labels, ) if routespec.startswith('/'): host = None path = routespec else: host, path = routespec.split('/', 1) target_parts = urlparse(target) target_ip = target_parts.hostname target_port = target_parts.port target_is_ip = re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', target_ip) is not None # Make endpoint object if target_is_ip: endpoint = V1Endpoints( kind='Endpoints', metadata=meta, subsets=[ V1EndpointSubset(addresses=[V1EndpointAddress(ip=target_ip)], ports=[V1EndpointPort(port=target_port)]) ]) else: endpoint = None # Make service object if target_is_ip: service = V1Service(kind='Service', metadata=meta, spec=V1ServiceSpec(type='ClusterIP', external_name='', ports=[ V1ServicePort( port=target_port, target_port=target_port) ])) else: service = V1Service( kind='Service', metadata=meta, spec=V1ServiceSpec( type='ExternalName', external_name=target_ip, cluster_ip='', ports=[ V1ServicePort(port=target_port, target_port=target_port) ], ), ) # Make Ingress object ingress = ExtensionsV1beta1Ingress( kind='Ingress', metadata=meta, spec=ExtensionsV1beta1IngressSpec(rules=[ ExtensionsV1beta1IngressRule( host=host, http=ExtensionsV1beta1HTTPIngressRuleValue(paths=[ ExtensionsV1beta1HTTPIngressPath( path=path, backend=ExtensionsV1beta1IngressBackend( service_name=name, service_port=target_port)) ])) ])) return endpoint, service, ingress
def make_ingress(name, routespec, target, data): """ Returns an ingress, service, endpoint object that'll work for this service """ # move beta imports here, # which are more sensitive to kubernetes version # and will change when they move out of beta from kubernetes.client.models import ( V1beta1Ingress, V1beta1IngressSpec, V1beta1IngressRule, V1beta1HTTPIngressRuleValue, V1beta1HTTPIngressPath, V1beta1IngressBackend, ) meta = V1ObjectMeta(name=name, annotations={ 'hub.jupyter.org/proxy-data': json.dumps(data), 'hub.jupyter.org/proxy-routespec': routespec, 'hub.jupyter.org/proxy-target': target }, labels={ 'heritage': 'jupyterhub', 'component': 'singleuser-server', 'hub.jupyter.org/proxy-route': 'true' }) if routespec.startswith('/'): host = None path = routespec else: host, path = routespec.split('/', 1) target_parts = urlparse(target) target_ip = target_parts.hostname target_port = target_parts.port target_is_ip = re.match('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', target_ip) is not None # Make endpoint object if target_is_ip: endpoint = V1Endpoints( kind='Endpoints', metadata=meta, subsets=[ V1EndpointSubset(addresses=[V1EndpointAddress(ip=target_ip)], ports=[V1EndpointPort(port=target_port)]) ]) else: endpoint = None # Make service object if target_is_ip: service = V1Service(kind='Service', metadata=meta, spec=V1ServiceSpec(type='ClusterIP', external_name='', ports=[ V1ServicePort( port=target_port, target_port=target_port) ])) else: service = V1Service( kind='Service', metadata=meta, spec=V1ServiceSpec( type='ExternalName', external_name=target_ip, cluster_ip='', ports=[ V1ServicePort(port=target_port, target_port=target_port) ], ), ) # Make Ingress object ingress = V1beta1Ingress( kind='Ingress', metadata=meta, spec=V1beta1IngressSpec(rules=[ V1beta1IngressRule(host=host, http=V1beta1HTTPIngressRuleValue(paths=[ V1beta1HTTPIngressPath( path=path, backend=V1beta1IngressBackend( service_name=name, service_port=target_port)) ])) ])) return endpoint, service, ingress
def start(self): """Set custom configuration during start before calling the super.start method of Dockerspawner""" self.saved_user_options = self.user_options if self.user_options.get(utils.OPTION_IMAGE): self.image = self.user_options.get(utils.OPTION_IMAGE) # Set request explicitly to 0, otherwise Kubernetes will set it to the same amount as limit # self.cpu_guarantee / self.mem_guarantee cannot be directly used, as they are of type ByteSpecification and, for example, 0G will be transformed to 0 which will not pass # the 'if cpu_guarantee' check (see https://github.com/jupyterhub/kubespawner/blob/8a6d66e04768565c0fc56c790a5fc42bfee634ec/kubespawner/objects.py#L279). # Hence, set it via extra_resource_guarantees. self.extra_resource_guarantees = {"cpu": 0, "memory": "0G"} if self.user_options.get(utils.OPTION_CPU_LIMIT): self.cpu_limit = float( self.user_options.get(utils.OPTION_CPU_LIMIT)) if self.user_options.get(utils.OPTION_MEM_LIMIT): memory = str(self.user_options.get(utils.OPTION_MEM_LIMIT)) + "G" self.mem_limit = memory.upper().replace("GB", "G").replace( "KB", "K").replace("MB", "M").replace("TB", "T") #if self.user_options.get('is_mount_volume') == 'on': # {username} and {servername} will be automatically replaced by DockerSpawner with the right values as in template_namespace # self.volumes = {'jhub-user-{username}{servername}': "/workspace"} # set default label 'origin' to know for sure which containers where started via the hub #self.extra_labels['pod_name'] = self.pod_name if self.user_options.get(utils.OPTION_DAYS_TO_LIVE): days_to_live_in_seconds = int( self.user_options.get(utils.OPTION_DAYS_TO_LIVE) ) * 24 * 60 * 60 # days * hours_per_day * minutes_per_hour * seconds_per_minute expiration_timestamp = time.time() + days_to_live_in_seconds self.extra_labels[utils.LABEL_EXPIRATION_TIMESTAMP] = str( expiration_timestamp) else: self.extra_labels[utils.LABEL_EXPIRATION_TIMESTAMP] = str(0) #if self.user_options.get('gpus'): # extra_host_config['runtime'] = "nvidia" # self.extra_labels[LABEL_NVIDIA_VISIBLE_DEVICES] = self.user_options.get('gpus') res = yield super().start() # Create service for pod so that it can be routed via name service = V1Service( kind='Service', spec=V1ServiceSpec( type='ClusterIP', ports=[V1ServicePort(port=self.port, target_port=self.port)], selector={ utils.LABEL_MLHUB_ORIGIN: self.extra_labels[utils.LABEL_MLHUB_ORIGIN], LABEL_POD_NAME: self.extra_labels[LABEL_POD_NAME] }), metadata=V1ObjectMeta(name=self.pod_name, labels=self.extra_labels)) try: yield self.asynchronize(self.api.create_namespaced_service, namespace=self.namespace, body=service) except client.rest.ApiException as e: if e.status == 409: self.log.info( 'Service {} already existed. No need to re-create.'.format( self.pod_name)) return res