Exemple #1
0
    def _build_cvmfs_volume_mount(self, cvmfs_repos):
        """Build the Volume and VolumeMount necessary to enable CVMFS.

        :param cvmfs_mounts: List of CVMFS repos to make available. They
            should be part of ``reana_commons.config.CVMFS_REPOSITORIES``.
        """
        cvmfs_map = {}
        volumes = []
        volume_mounts = []
        for repo in cvmfs_repos:
            if repo in CVMFS_REPOSITORIES:
                cvmfs_map[CVMFS_REPOSITORIES[repo]] = repo

        for repo_name, path in cvmfs_map.items():
            volume = get_k8s_cvmfs_volume(repo_name)
            volumes.append(volume)
            volume_mounts.append(
                {
                    "name": volume["name"],
                    "mountPath": "/cvmfs/{}".format(path),
                    "readOnly": volume["readOnly"],
                }
            )

        return volumes, volume_mounts
Exemple #2
0
    def execute(self):
        """Execute a job in Kubernetes."""
        backend_job_id = str(uuid.uuid4())
        job = {
            'kind': 'Job',
            'apiVersion': 'batch/v1',
            'metadata': {
                'name': backend_job_id,
                'namespace': K8S_DEFAULT_NAMESPACE
            },
            'spec': {
                'backoffLimit': MAX_JOB_RESTARTS,
                'autoSelector': True,
                'template': {
                    'metadata': {
                        'name': backend_job_id
                    },
                    'spec': {
                        'containers': [
                            {
                                'image': self.docker_img,
                                'command': self.cmd,
                                'name': backend_job_id,
                                'env': [],
                                'volumeMounts': []
                            },
                        ],
                        'volumes': [],
                        'restartPolicy':
                        'Never'
                    }
                }
            }
        }

        if self.env_vars:
            for var, value in self.env_vars.items():
                job['spec']['template']['spec']['containers'][0]['env'].append(
                    {
                        'name': var,
                        'value': value
                    })

        if self.shared_file_system:
            self.add_shared_volume(job)

        if self.cvmfs_mounts != 'false':
            cvmfs_map = {}
            for cvmfs_mount_path in ast.literal_eval(self.cvmfs_mounts):
                if cvmfs_mount_path in CVMFS_REPOSITORIES:
                    cvmfs_map[
                        CVMFS_REPOSITORIES[cvmfs_mount_path]] =  \
                            cvmfs_mount_path

            for repository, mount_path in cvmfs_map.items():
                volume = get_k8s_cvmfs_volume(repository)

                (job['spec']['template']['spec']['containers'][0]
                 ['volumeMounts'].append({
                     'name':
                     volume['name'],
                     'mountPath':
                     '/cvmfs/{}'.format(mount_path)
                 }))
                job['spec']['template']['spec']['volumes'].append(volume)

        # add better handling
        try:
            api_response = \
                current_k8s_batchv1_api_client.create_namespaced_job(
                    namespace=K8S_DEFAULT_NAMESPACE, body=job)
            return backend_job_id
        except ApiException as e:
            logging.debug("Error while connecting to Kubernetes"
                          " API: {}".format(e))
        except Exception as e:
            logging.error(traceback.format_exc())
            logging.debug("Unexpected error: {}".format(e))
Exemple #3
0
def k8s_instantiate_job(job_id,
                        workflow_workspace,
                        docker_img,
                        cmd,
                        cvmfs_mounts,
                        env_vars,
                        shared_file_system,
                        job_type,
                        namespace='default'):
    """Create Kubernetes job.

    :param job_id: Job uuid.
    :param workflow_workspace: Absolute path to the job's workflow workspace.
    :param docker_img: Docker image to run the job.
    :param cmd: Command provided to the docker container.
    :param cvmfs_mounts: List of CVMFS volumes to mount in job pod.
    :param env_vars: Dictionary representing environment variables
        as {'var_name': 'var_value'}.
    :param namespace: Job's namespace.
    :shared_file_system: Boolean which represents whether the job
        should have a shared file system mounted.
    :returns: A :class:`kubernetes.client.models.v1_job.V1Job` corresponding
        to the created job, None if the creation could not take place.
    """
    job = {
        'kind': 'Job',
        'apiVersion': 'batch/v1',
        'metadata': {
            'name': job_id,
            'namespace': namespace
        },
        'spec': {
            'backoffLimit': app.config['MAX_JOB_RESTARTS'],
            'autoSelector': True,
            'template': {
                'metadata': {
                    'name': job_id
                },
                'spec': {
                    'containers': [
                        {
                            'name': job_id,
                            'image': docker_img,
                            'env': [],
                            'volumeMounts': []
                        },
                    ],
                    'volumes': [],
                    'restartPolicy':
                    'Never'
                }
            }
        }
    }

    if cmd:
        import shlex
        (job['spec']['template']['spec']['containers'][0]['command']
         ) = shlex.split(cmd)

    if env_vars:
        for var, value in env_vars.items():
            job['spec']['template']['spec']['containers'][0]['env'].append({
                'name':
                var,
                'value':
                value
            })

    if shared_file_system:
        add_shared_volume(job, workflow_workspace)

    if cvmfs_mounts != 'false':
        cvmfs_map = {}
        for cvmfs_mount_path in ast.literal_eval(cvmfs_mounts):
            if cvmfs_mount_path in CVMFS_REPOSITORIES:
                cvmfs_map[
                    CVMFS_REPOSITORIES[cvmfs_mount_path]] = cvmfs_mount_path

        for repository, mount_path in cvmfs_map.items():
            volume = get_k8s_cvmfs_volume(repository)

            (job['spec']['template']['spec']['containers'][0]
             ['volumeMounts'].append({
                 'name':
                 volume['name'],
                 'mountPath':
                 '/cvmfs/{}'.format(mount_path)
             }))
            job['spec']['template']['spec']['volumes'].append(volume)

    # add better handling
    try:
        api_response = \
            current_k8s_batchv1_api_client.create_namespaced_job(
                namespace=namespace, body=job)
        return api_response
    except client.rest.ApiException as e:
        logging.debug("Error while connecting to Kubernetes API: {}".format(e))
    except Exception as e:
        logging.error(traceback.format_exc())
        logging.debug("Unexpected error: {}".format(e))
    def execute(self):
        """Execute a job in Kubernetes."""
        backend_job_id = build_unique_component_name("run-job")
        self.job = {
            "kind": "Job",
            "apiVersion": "batch/v1",
            "metadata": {
                "name": backend_job_id,
                "namespace": REANA_RUNTIME_KUBERNETES_NAMESPACE,
            },
            "spec": {
                "automountServiceAccountToken": False,
                "backoffLimit": KubernetesJobManager.MAX_NUM_JOB_RESTARTS,
                "autoSelector": True,
                "template": {
                    "metadata": {
                        "name": backend_job_id,
                        "labels": {"reana-run-job-workflow-uuid": self.workflow_uuid},
                    },
                    "spec": {
                        "containers": [
                            {
                                "image": self.docker_img,
                                "command": ["bash", "-c"],
                                "args": [self.cmd],
                                "name": "job",
                                "env": [],
                                "volumeMounts": [],
                            }
                        ],
                        "initContainers": [],
                        "volumes": [],
                        "restartPolicy": "Never",
                        "enableServiceLinks": False,
                    },
                },
            },
        }
        user_id = os.getenv("REANA_USER_ID")
        secrets_store = REANAUserSecretsStore(user_id)

        secret_env_vars = secrets_store.get_env_secrets_as_k8s_spec()
        job_spec = self.job["spec"]["template"]["spec"]
        job_spec["containers"][0]["env"].extend(secret_env_vars)
        job_spec["volumes"].append(secrets_store.get_file_secrets_volume_as_k8s_specs())

        secrets_volume_mount = secrets_store.get_secrets_volume_mount_as_k8s_spec()
        job_spec["containers"][0]["volumeMounts"].append(secrets_volume_mount)

        if self.env_vars:
            for var, value in self.env_vars.items():
                job_spec["containers"][0]["env"].append({"name": var, "value": value})

        self.add_memory_limit(job_spec)
        self.add_hostpath_volumes()
        self.add_workspace_volume()
        self.add_shared_volume()
        self.add_eos_volume()
        self.add_image_pull_secrets()
        self.add_kubernetes_job_timeout()

        if self.cvmfs_mounts != "false":
            cvmfs_map = {}
            for cvmfs_mount_path in ast.literal_eval(self.cvmfs_mounts):
                if cvmfs_mount_path in CVMFS_REPOSITORIES:
                    cvmfs_map[CVMFS_REPOSITORIES[cvmfs_mount_path]] = cvmfs_mount_path

            for repository, mount_path in cvmfs_map.items():
                volume = get_k8s_cvmfs_volume(repository)

                (
                    job_spec["containers"][0]["volumeMounts"].append(
                        {
                            "name": volume["name"],
                            "mountPath": "/cvmfs/{}".format(mount_path),
                            "readOnly": volume["readOnly"],
                        }
                    )
                )
                job_spec["volumes"].append(volume)

        self.job["spec"]["template"]["spec"][
            "securityContext"
        ] = client.V1PodSecurityContext(
            run_as_group=WORKFLOW_RUNTIME_USER_GID, run_as_user=self.kubernetes_uid
        )

        if self.kerberos:
            self._add_krb5_init_container(secrets_store)

        if self.voms_proxy:
            self._add_voms_proxy_init_container(secrets_volume_mount, secret_env_vars)

        if REANA_RUNTIME_JOBS_KUBERNETES_NODE_LABEL:
            self.job["spec"]["template"]["spec"][
                "nodeSelector"
            ] = REANA_RUNTIME_JOBS_KUBERNETES_NODE_LABEL

        backend_job_id = self._submit()
        return backend_job_id
    def execute(self):
        """Execute a job in Kubernetes."""
        backend_job_id = str(uuid.uuid4())
        self.job = {
            'kind': 'Job',
            'apiVersion': 'batch/v1',
            'metadata': {
                'name': backend_job_id,
                'namespace': K8S_DEFAULT_NAMESPACE
            },
            'spec': {
                'backoffLimit': KubernetesJobManager.MAX_NUM_JOB_RESTARTS,
                'autoSelector': True,
                'template': {
                    'metadata': {
                        'name': backend_job_id
                    },
                    'spec': {
                        'containers': [
                            {
                                'image': self.docker_img,
                                'command': self.cmd,
                                'name': 'job',
                                'env': [],
                                'volumeMounts': [],
                            }
                        ],
                        'initContainers': [],
                        'volumes': [],
                        'restartPolicy': 'Never'
                    }
                }
            }
        }
        user_id = os.getenv('REANA_USER_ID')
        secrets_store = REANAUserSecretsStore(user_id)

        secret_env_vars = secrets_store.get_env_secrets_as_k8s_spec()
        self.job['spec']['template']['spec']['containers'][0]['env'].extend(
            secret_env_vars
        )

        self.job['spec']['template']['spec']['volumes'].append(
            secrets_store.get_file_secrets_volume_as_k8s_specs()
        )

        secrets_volume_mount = \
            secrets_store.get_secrets_volume_mount_as_k8s_spec()
        self.job['spec']['template']['spec']['containers'][0]['volumeMounts'] \
            .append(secrets_volume_mount)

        if self.env_vars:
            for var, value in self.env_vars.items():
                self.job['spec']['template']['spec'][
                    'containers'][0]['env'].append({'name': var,
                                                    'value': value})

        self.add_hostpath_volumes()
        self.add_shared_volume()
        self.add_eos_volume()
        self.add_image_pull_secrets()

        if self.cvmfs_mounts != 'false':
            cvmfs_map = {}
            for cvmfs_mount_path in ast.literal_eval(self.cvmfs_mounts):
                if cvmfs_mount_path in CVMFS_REPOSITORIES:
                    cvmfs_map[
                        CVMFS_REPOSITORIES[cvmfs_mount_path]] = \
                            cvmfs_mount_path

            for repository, mount_path in cvmfs_map.items():
                volume = get_k8s_cvmfs_volume(repository)

                (self.job['spec']['template']['spec']['containers'][0]
                    ['volumeMounts'].append(
                        {'name': volume['name'],
                         'mountPath': '/cvmfs/{}'.format(mount_path),
                         'readOnly': volume['readOnly']}
                ))
                self.job['spec']['template']['spec']['volumes'].append(volume)

        self.job['spec']['template']['spec']['securityContext'] = \
            client.V1PodSecurityContext(
                run_as_group=WORKFLOW_RUNTIME_USER_GID,
                run_as_user=self.kubernetes_uid)

        if self.kerberos:
            self._add_krb5_init_container(secrets_volume_mount)

        backend_job_id = self._submit()
        return backend_job_id