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
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))
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