예제 #1
0
    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
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
 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())
예제 #7
0
 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
     ])
예제 #8
0
    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
예제 #9
0
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
예제 #10
0
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
예제 #11
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)
예제 #12
0
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)
예제 #13
0
    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
예제 #14
0
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/")
예제 #15
0
 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
예제 #16
0
 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
예제 #18
0
 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
예제 #19
0
    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)
예제 #20
0
    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)
예제 #21
0
    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']))
예제 #22
0
    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)
예제 #23
0
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()
예제 #24
0
    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()
예제 #25
0
    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)
예제 #26
0
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)
예제 #27
0
    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': [],
         }
     }
예제 #29
0
 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
예제 #30
0
    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