def create_namespace(self, namespace=None, kube_config=None): """Create a namespace in a k8s cluster Parameters ---------- namespace: str a namespace for k8s working with kube_config: kubernetes.client.configuration.Configuration the configuration to the kubernetes cluster Returns ------- V1Namespace (https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1Namespace.md) """ if kube_config: api_client = ApiClient(kube_config) else: api_client = ApiClient() v1 = client.CoreV1Api(api_client) logger.debug('Creating namespace % s' % namespace) for ns in v1.list_namespace().items: if ns.metadata.name == namespace: logger.warning('Namespace %s already exists' % namespace) return None body = client.V1Namespace() body.metadata = client.V1ObjectMeta(name=namespace) return v1.create_namespace(body)
def create_configmap(self, kube_config=None, configmap=None, file=None, namespace="default", configmap_name="Configmap_name"): if configmap is None and file is None: raise Exception( "Please provide either a configmap or a file to create a Kubernetes configmap") if kube_config: api_client = ApiClient(kube_config) else: api_client = ApiClient() # Configureate ConfigMap metadata metadata = client.V1ObjectMeta(name=configmap_name, namespace=namespace) v1 = client.CoreV1Api(api_client) if file is not None: file_name = file.split('/')[-1] logger.info('Creating configmap object from file %s' % file_name) # Get File Content with open(file, 'r') as f: file_content = f.read() data = {file_name: file_content} # Instantiate the configmap object configmap = client.V1ConfigMap(api_version="v1", kind="ConfigMap", data=data, metadata=metadata) try: logger.info('Deploying configmap') v1.create_namespaced_config_map(namespace=namespace, body=configmap,) logger.debug('Deploy configmap successfully') except FailToCreateError as e: for api_exception in e.api_exceptions: body = json.loads(api_exception.body) logger.error('Error: %s, because: %s' % (api_exception.reason, body['message']))
def get_k8s_pod_log(self, pod_name, kube_config=None, kube_namespace='default'): '''Get the log of a given pod Parameters ---------- pod_name: string the name of the pod to get log kube_config: kubernetes.client.configuration.Configuration the configuration to the kubernetes cluster kube_namespace: string the k8s namespace to perform the k8s resources operation on, the default namespace is 'default' Returns ------- string the content of the log ''' if kube_config: api_client = ApiClient(kube_config) else: api_client = ApiClient() v1 = client.CoreV1Api(api_client) log = v1.read_namespaced_pod_log(name=pod_name, namespace=kube_namespace) return log
def get_k8s_endpoint_ip(self, service_name, kube_config=None, kube_namespace='default'): '''Get the endpoint ip of a k8s service Parameters ---------- service_name: string the name of the service kube_config: kubernetes.client.configuration.Configuration the configuration to the kubernetes cluster kube_namespace: string the k8s namespace to perform the wait of k8s resources operation on, the default namespace is 'default' Returns ------- string the ip of a k8s endpoint ''' if kube_config: api_client = ApiClient(kube_config) else: api_client = ApiClient() v1 = client.CoreV1Api(api_client) endpoints = v1.read_namespaced_endpoints(name=service_name, namespace=kube_namespace) if endpoints and endpoints.subsets: if endpoints.subsets[0].addresses: return endpoints.subsets[0].addresses[0].ip return None
def get_k8s_resources(self, resource, label_selectors='', kube_config=None, kube_namespace='default'): '''List all k8s resources in a namespace Parameters ---------- resource: string the name of the resource (job, pod, etc.) label_selectors: string the k8s labels used to filter to resource, the format is: key1=value1,key2=value2,... kube_config: kubernetes.client.configuration.Configuration the configuration to the kubernetes cluster kube_namespace: string the k8s namespace to perform the wait of k8s resources operation on, the default namespace is 'default' Returns ------- kubernetes resource type: V1JobList, V1PodList, etc. (ref: https://github.com/kubernetes-client/python/blob/master/kubernetes/README.md#documentation-for-models) ''' if kube_config: api_client = ApiClient(kube_config) else: api_client = ApiClient() if resource == 'job': v1 = client.BatchV1Api(api_client) list_resources = partial(v1.list_namespaced_job, namespace=kube_namespace) elif resource == 'pod': v1 = client.CoreV1Api(api_client) list_resources = partial(v1.list_namespaced_pod, namespace=kube_namespace) elif resource == 'namespace': v1 = client.CoreV1Api(api_client) list_resources = v1.list_namespace elif resource == 'node': v1 = client.CoreV1Api(api_client) list_resources = v1.list_node elif resource == 'service': v1 = client.CoreV1Api(api_client) list_resources = v1.list_service_for_all_namespaces else: logger.info('Not support this type of resource: %s' % resource) return False resources = list_resources(label_selector=label_selectors) return resources
def __init__(self, kube_config_file_path): """ Initialize with default values if not defined Note: Need to initialize parameters in test side to make this working. Not sure for reason. Parameters are initialized here to give tip for IDE which kind of classes those are. :param k8s_client: Kubernetes api client :param corev1: corev1 api client :param storage_class: storage class api client :param daemon: daemonset api client """ load_kube_config(config_file=kube_config_file_path) self.corev1 = CoreV1Api() self.storage_class = StorageV1Api() self.k8s_client = ApiClient(Configuration()) self.daemon = AppsV1Api(ApiClient())
def __init__(self): self.client = ApiClient() self._groups = self.get_api_groups() self._resources = flatten([ self.get_resources_for_group(*group_parts) for group_parts in self._groups ])
def __init__(self, api_url, kind, api_client=None): if api_client is None: api_client = ApiClient() self.api_client = api_client self.api_url = api_url self.kind = kind
def get_game_url_base_and_path(game_id: int) -> str: api_client = ApiClient() api_instance = CustomObjectsApi(api_client) result = api_instance.list_namespaced_custom_object( group="agones.dev", version="v1", namespace="default", plural="gameservers", label_selector=f"game-id={game_id}", ) try: result_items = result["items"] game_server = None # Get the first game server not marked for deletion. Raise 404 if there is none. for item in result_items: if "deletionTimestamp" not in item["metadata"]: game_server = item break if game_server is None: raise Http404 game_server_status = game_server["status"] return ( f"http://{game_server_status['address']}:{game_server_status['ports'][0]['port']}", "/socket.io", ) except (KeyError, IndexError): raise Http404
def main(): config.load_kube_config() client = DynamicClient(ApiClient()) ret = [] for resource in client.resources: key = '{}.{}'.format(resource.group_version, resource.kind) item = {} item[key] = { k: v for k, v in resource.__dict__.items() if k not in ('client', 'subresources', 'resource') } if isinstance(resource, ResourceList): item[key]["resource"] = '{}.{}'.format( resource.resource.group_version, resource.resource.kind) else: item[key]['subresources'] = {} for name, value in resource.subresources.items(): item[key]['subresources'][name] = { k: v for k, v in value.__dict__.items() if k != 'parent' } item[key]['urls'] = resource.urls ret.append(item) print( yaml.safe_dump(sorted(ret, key=lambda x: x.keys()[0].replace('List', '1')), default_flow_style=False)) return 0
def test_job_to_dict(): j = V1Job(api_version='abc', kind='foo') d = util.job_to_dict(j) assert d is not None assert isinstance(d, dict) assert d == ApiClient().sanitize_for_serialization(j)
def identify_kubernetes_object(data: Dict = None): """identify_kubernetes_object """ if data is None: data = {} api_version: str = "" kind: str = "" klass: str = "" try: api_version = _fix_api_version(data["apiVersion"].upper()) kind = data["kind"] klass = api_version + kind except KeyError as error: track = traceback.format_exc() LOGGER.error(error) LOGGER.debug(track) if not klass: return None try: client = ApiClient() obj = client._ApiClient__deserialize(data, klass) return obj except AttributeError as error: track = traceback.format_exc() LOGGER.error(error) LOGGER.debug(track)
def submit_job( self, job_spec: JobSpec, name: str, labels: Optional[Dict[str, str]] = None, ) -> Optional[Job]: '''submits a job to the cluster based on the given job spec''' v1job = self.create_v1job(job_spec=job_spec, name=name, labels=labels) submitted = self.submit_v1job(v1job) container = job_spec.spec['template']['spec']['containers'][0]['image'] if submitted is not None: details = { 'cluster_name': self.name, 'project_id': self.project_id, 'cluster_zone': self.zone, 'job': ApiClient().sanitize_for_serialization(submitted), } return Job( spec=job_spec, container=container, details=details, status=JobStatus.SUBMITTED, ) return None
def generate_pod_yaml(args): """Generates yaml files for each task in the DAG. Used for testing output of KubernetesExecutor""" execution_date = args.execution_date dag = get_dag(subdir=args.subdir, dag_id=args.dag_id) yaml_output_path = args.output_path kube_config = KubeConfig() for task in dag.tasks: ti = TaskInstance(task, execution_date) pod = PodGenerator.construct_pod( dag_id=args.dag_id, task_id=ti.task_id, pod_id=create_pod_id(args.dag_id, ti.task_id), try_number=ti.try_number, kube_image=kube_config.kube_image, date=ti.execution_date, args=ti.command_as_list(), pod_override_object=PodGenerator.from_obj(ti.executor_config), scheduler_job_id="worker-config", namespace=kube_config.executor_namespace, base_worker_pod=PodGenerator.deserialize_model_file(kube_config.pod_template_file), ) pod_mutation_hook(pod) api_client = ApiClient() date_string = pod_generator.datetime_to_label_safe_datestring(execution_date) yaml_file_name = f"{args.dag_id}_{ti.task_id}_{date_string}.yml" os.makedirs(os.path.dirname(yaml_output_path + "/airflow_yaml_output/"), exist_ok=True) with open(yaml_output_path + "/airflow_yaml_output/" + yaml_file_name, "w") as output: sanitized_pod = api_client.sanitize_for_serialization(pod) output.write(yaml.dump(sanitized_pod)) print(f"YAML output can be found at {yaml_output_path}/airflow_yaml_output/")
def deserialize_model_dict(pod_dict: dict) -> k8s.V1Pod: """ Deserializes python dictionary to k8s.V1Pod @param pod_dict: @return: """ api_client = ApiClient() return api_client._ApiClient__deserialize_model(pod_dict, k8s.V1Pod) # pylint: disable=W0212
def serialize_pod(pod: k8s.V1Pod): """ Converts a k8s.V1Pod into a jsonified object @param pod: @return: """ api_client = ApiClient() return api_client.sanitize_for_serialization(pod)
def __init__(self, api_client=None): config = Configuration() if api_client: self.api_client = api_client else: if not config.api_client: config.api_client = ApiClient() self.api_client = config.api_client
def __init__(self) -> None: if os.path.exists(SERVICE_TOKEN_FILENAME): load_incluster_config() else: load_kube_config() self.api = ApiClient() version_api = VersionApi(self.api) self._is_openshift = "eks" not in version_api.get_code().git_version
def set_labels_node(self, nodename, labels, kube_config=None): """Set label for a node Parameters ---------- nodename: str hostname of the node labels: string the new k8s labels used to label this node, the format is: key1=value1,key2=value2,... kube_config: kubernetes.client.configuration.Configuration the configuration to the kubernetes cluster Returns ------- V1Node (https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1Node.md) if label node successfully None if label node unsuccessfully """ if kube_config: api_client = ApiClient(kube_config) else: api_client = ApiClient() v1 = client.CoreV1Api(api_client) logger.debug('Label node %s with %s' % (nodename, labels)) for node in v1.list_node().items: if node.metadata.name == nodename: break else: logger.warning('Node %s does not exist' % nodename) return None body = { 'metadata': { 'labels': dict() } } for label in labels.strip().split(','): key, val = label.strip().split('=') body['metadata']['labels'][key] = val return v1.patch_node(name=nodename, body=body)
def deserialize_model_dict(pod_dict: dict) -> k8s.V1Pod: """ Deserializes python dictionary to k8s.V1Pod :param pod_dict: Serialized dict of k8s.V1Pod object :return: De-serialized k8s.V1Pod """ api_client = ApiClient() return api_client._ApiClient__deserialize_model(pod_dict, k8s.V1Pod)
def deploy_k8s_resources(self, path=None, files=None, kube_config=None, namespace="default"): """Deploy k8s resources on a k8s cluster from deployment yaml files Parameters ---------- path: str the path to the directory which stores all the deployment yaml files files: list a list of yaml files to use for deployment kube_config: kubernetes.client.configuration.Configuration the configuration to the kubernetes cluster namespace: str a namespace for k8s working with """ if kube_config: api_client = ApiClient(kube_config) else: api_client = ApiClient() if path is not None: files = list() for file in os.listdir(path): if file.endswith('.yaml'): files.append(os.path.join(path, file)) for file in files: logger.info('--> Deploying file %s' % file.split('/')[-1]) try: utils.create_from_yaml(k8s_client=api_client, yaml_file=file, namespace=namespace) logger.debug('Deploy file %s successfully' % file) except FailToCreateError as e: for api_exception in e.api_exceptions: body = json.loads(api_exception.body) logger.error('Error: %s, because: %s' % (api_exception.reason, body['message']))
def serialize_pod(pod: k8s.V1Pod) -> dict: """ Converts a k8s.V1Pod into a jsonified object :param pod: k8s.V1Pod object :return: Serialized version of the pod returned as dict """ api_client = ApiClient() return api_client.sanitize_for_serialization(pod)
def _get_k8s_api_client() -> ApiClient: # Create new client everytime to avoid token refresh issues # https://github.com/kubernetes-client/python/issues/741 # https://github.com/kubernetes-client/python-base/issues/125 if bool( util.strtobool( os.environ.get('LOAD_IN_CLUSTER_KUBECONFIG', 'false'))): config.load_incluster_config() return ApiClient() return config.new_client_from_config()
def __init__(self, *args, **kwargs): self.networking_api = kubernetes.client.NetworkingV1beta1Api() self.api: CoreV1Api = kubernetes.client.CoreV1Api() self.secret_creator = TokenSecretCreator() self.api_client: ApiClient = ApiClient() self.custom_objects_api: CustomObjectsApi = CustomObjectsApi( self.api_client) super(KubernetesGameManager, self).__init__(*args, **kwargs) self._create_ingress_paths_for_existing_games()
def execute_command(self, pod_name, command, kube_config=None, kube_namespace='default'): """Execute a command on a pod Parameters ---------- pod_name: string the name of the pod to run the command command: string the command to run on the pod kube_config: kubernetes.client.configuration.Configuration the configuration to the kubernetes cluster kube_namespace: string the k8s namespace to perform the k8s resources operation on, the default namespace is 'default' Returns ------- string the std output when run the command in the pod """ if kube_config: api_client = ApiClient(kube_config) else: api_client = ApiClient() v1 = client.CoreV1Api(api_client) logger.debug('Run command %s on pod %s' % (command, pod_name)) if ' ' in command: command = _split_argument(command) return stream(v1.connect_get_namespaced_pod_exec, pod_name, namespace=kube_namespace, command=command, stderr=True, stdin=False, stdout=True, tty=False, _preload_content=True)
def api_init(kube_config_file=None, host=None, token_filename=None, cert_filename=None, context=None): global CoreV1Api global RbacAuthorizationV1Api global api_temp if host and token_filename: # remotely token_filename = os.path.abspath(token_filename) if cert_filename: cert_filename = os.path.abspath(cert_filename) BearerTokenLoader(host=host, token_filename=token_filename, cert_filename=cert_filename).load_and_set() CoreV1Api = client.CoreV1Api() RbacAuthorizationV1Api = client.RbacAuthorizationV1Api() api_temp = ApiClientTemp() elif kube_config_file: config.load_kube_config(os.path.abspath(kube_config_file)) CoreV1Api = client.CoreV1Api() RbacAuthorizationV1Api = client.RbacAuthorizationV1Api() api_from_config = config.new_client_from_config(kube_config_file) api_temp = ApiClientTemp(configuration=api_from_config.configuration) else: configuration = Configuration() api_client = ApiClient() if running_in_docker_container(): # TODO: Consider using config.load_incluster_config() from container created by Kubernetes. Required service account with privileged permissions. # Must have mounted volume container_volume_prefix = '/tmp' kube_config_bak_path = '/KubiScan/config_bak' if not os.path.isfile(kube_config_bak_path): copyfile(container_volume_prefix + os.path.expandvars('$CONF_PATH'), kube_config_bak_path) replace(kube_config_bak_path, ': /', ': /tmp/') config.load_kube_config(kube_config_bak_path, context=context, client_configuration=configuration) else: config.load_kube_config(context=context, client_configuration=configuration) api_client = ApiClient(configuration=configuration) CoreV1Api = client.CoreV1Api(api_client=api_client) RbacAuthorizationV1Api = client.RbacAuthorizationV1Api(api_client=api_client) api_temp = ApiClientTemp(configuration=configuration)
def _get_client_with_patched_configuration(cfg: Optional[Configuration]) -> client.CoreV1Api: """ This is a workaround for supporting api token refresh in k8s client. The function can be replace with `return client.CoreV1Api()` once the upstream client supports token refresh. """ if cfg: return client.CoreV1Api(api_client=ApiClient(configuration=cfg)) else: return client.CoreV1Api()
def setUp(self): self.maxDiff = None # pylint: disable=invalid-name self.api_client = ApiClient() self.expected_pod = { 'apiVersion': 'v1', 'kind': 'Pod', 'metadata': { 'namespace': 'default', 'name': ANY, 'annotations': {}, 'labels': { 'foo': 'bar', 'kubernetes_pod_operator': 'True', 'airflow_version': airflow_version.replace('+', '-') } }, 'spec': { 'affinity': {}, 'containers': [{ 'image': 'ubuntu:16.04', 'args': ["echo 10"], 'command': ["bash", "-cx"], 'env': [], 'imagePullPolicy': 'IfNotPresent', 'envFrom': [], 'name': 'base', 'ports': [], 'resources': { 'limits': { 'cpu': None, 'memory': None, 'nvidia.com/gpu': None }, 'requests': { 'cpu': None, 'memory': None } }, 'volumeMounts': [], }], 'hostNetwork': False, 'imagePullSecrets': [], 'initContainers': [], 'nodeSelector': {}, 'restartPolicy': 'Never', 'securityContext': {}, 'serviceAccountName': 'default', 'tolerations': [], 'volumes': [], } }
def client(self) -> ApiClient: """Get Kubernetes client configured from kubeconfig""" config = Configuration() try: if self.local: load_incluster_config(client_configuration=config) else: load_kube_config_from_dict(self.kubeconfig, client_configuration=config) return ApiClient(config) except ConfigException as exc: raise ServiceConnectionInvalid from exc
def delete_namespace(self, namespace=None, kube_config=None): """Delete a namespace from a k8s cluster Parameters ---------- namespace: str a namespace for k8s working with kube_config: kubernetes.client.configuration.Configuration the configuration to the kubernetes cluster Returns ------- bool True: delete successfully False: delete unsuccessfully """ if kube_config: api_client = ApiClient(kube_config) else: api_client = ApiClient() v1 = client.CoreV1Api(api_client) logger.debug('Deleting namespace %s' % namespace) for ns in v1.list_namespace().items: if ns.metadata.name == namespace: v1.delete_namespace(name=namespace) logger.debug('Waiting for namespace %s to be deleted' % namespace) for i in range(100): for ns in v1.list_namespace().items: if ns.metadata.name == namespace: sleep(5) break else: return True else: logger.warning('Namespace %s does not exist' % namespace) return False