From 268b5e70b24527a36cc48185a86f8be8fd236c2c Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Tue, 13 Nov 2018 10:33:19 +0100 Subject: [PATCH 01/19] Upgrade to Aien4Cloud 2.1 SM7 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 6c7a2e19..d7e61f3f 100644 --- a/pom.xml +++ b/pom.xml @@ -21,12 +21,12 @@ alien4cloud alien4cloud-parent - 2.1.0-SNAPSHOT + 2.1.0-SM7 - 2.1.0-SNAPSHOT - 2.1.0-SNAPSHOT + 2.1.0-SM7 + 2.1.0-SM7 1.0.0-ALIEN20 alien_dsl_2_0_0 From 75259e554ea77c422d2ccbb852664a3f2a8375d8 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Wed, 14 Nov 2018 16:07:53 +0100 Subject: [PATCH 02/19] Update Slurm types --- alien4cloud-yorc-plugin/pom.xml | 2 +- .../resources/commons/resources/yorc-types.yaml | 2 -- .../main/resources/slurm/resources/resources.yaml | 15 ++++++++++++++- .../yorc/samples/job/srun/component/types.yaml | 4 ++-- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/alien4cloud-yorc-plugin/pom.xml b/alien4cloud-yorc-plugin/pom.xml index 455524dd..b66482ce 100644 --- a/alien4cloud-yorc-plugin/pom.xml +++ b/alien4cloud-yorc-plugin/pom.xml @@ -39,7 +39,7 @@ 1.0.0 2.0.0-SNAPSHOT 1.0.0 - 1.0.0 + 1.1.0-SNAPSHOT diff --git a/alien4cloud-yorc-plugin/src/main/resources/commons/resources/yorc-types.yaml b/alien4cloud-yorc-plugin/src/main/resources/commons/resources/yorc-types.yaml index 19b7b7cd..dbd1c9eb 100644 --- a/alien4cloud-yorc-plugin/src/main/resources/commons/resources/yorc-types.yaml +++ b/alien4cloud-yorc-plugin/src/main/resources/commons/resources/yorc-types.yaml @@ -75,5 +75,3 @@ node_types: endpoint: type: yorc.capabilities.Endpoint.ProvisioningAdmin - # NOTE: Alien specific - diff --git a/alien4cloud-yorc-plugin/src/main/resources/slurm/resources/resources.yaml b/alien4cloud-yorc-plugin/src/main/resources/slurm/resources/resources.yaml index 61a94590..c42d9de6 100644 --- a/alien4cloud-yorc-plugin/src/main/resources/slurm/resources/resources.yaml +++ b/alien4cloud-yorc-plugin/src/main/resources/slurm/resources/resources.yaml @@ -8,6 +8,7 @@ description: "Defines resources for the Yorc plugin, slurm configuration." imports: - tosca-normative-types:${tosca.normative.types.version} + - alien-base-types:${alien4cloud.version} - yorc-types:${yorc.types.version} @@ -117,10 +118,22 @@ node_types: description: The ID of the job. interfaces: tosca.interfaces.node.lifecycle.Runnable: - run: + submit: implementation: file: type: yorc.artifacts.Deployment.SlurmJob + run: + implementation: + # This is a hack to force Alien to generate this step in workflows it will be overrided in Yorc + # TODO(loicalbertin) think about use a topology modifier for this to add this step only if a submit operation exists + file: "resources.yaml" + type: yorc.artifacts.Deployment.SlurmJob + cancel: + implementation: + # This is a hack to force Alien to generate this step in workflows it will be overrided in Yorc + # TODO(loicalbertin) think about use a topology modifier for this to add this step only if a submit operation exists + file: "resources.yaml" + type: yorc.artifacts.Deployment.SlurmJob yorc.nodes.slurm.SingularityJob: derived_from: yorc.nodes.slurm.Job diff --git a/tosca-samples/org/ystia/yorc/samples/job/srun/component/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/srun/component/types.yaml index 61be733f..7dff7c1e 100644 --- a/tosca-samples/org/ystia/yorc/samples/job/srun/component/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/job/srun/component/types.yaml @@ -24,7 +24,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - yorc-types:1.0.0 - - yorc-slurm-types:1.0.0 + - yorc-slurm-types:1.1.0-SNAPSHOT node_types: org.ystia.yorc.samples.job.srun.Component: @@ -35,7 +35,7 @@ node_types: icon: /images/slurm.png interfaces: tosca.interfaces.node.lifecycle.Runnable: - run: + submit: inputs: args: {get_property: [SELF, exec_args]} implementation: From 5c457a3857c706a9606d1ccdf016de1f0e2e0cc1 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Thu, 22 Nov 2018 09:53:03 +0100 Subject: [PATCH 03/19] Update Slurm imports --- .../org/ystia/yorc/samples/job/sbatch/component/types.yaml | 4 ++-- .../ystia/yorc/samples/job/singularity/component/types.yaml | 2 +- .../ystia/yorc/samples/job/singularity/topology/types.yaml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tosca-samples/org/ystia/yorc/samples/job/sbatch/component/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/sbatch/component/types.yaml index dd1f7a94..71b087bf 100644 --- a/tosca-samples/org/ystia/yorc/samples/job/sbatch/component/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/job/sbatch/component/types.yaml @@ -24,7 +24,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - yorc-types:1.0.0 - - yorc-slurm-types:1.0.0 + - yorc-slurm-types:1.1.0-SNAPSHOT node_types: org.ystia.yorc.samples.job.sbatch.Component: @@ -39,7 +39,7 @@ node_types: file: bin interfaces: tosca.interfaces.node.lifecycle.Runnable: - run: + submit: inputs: args: {get_property: [SELF, exec_args]} implementation: diff --git a/tosca-samples/org/ystia/yorc/samples/job/singularity/component/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/singularity/component/types.yaml index d9acb65e..ff079488 100644 --- a/tosca-samples/org/ystia/yorc/samples/job/singularity/component/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/job/singularity/component/types.yaml @@ -24,7 +24,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - yorc-types:1.0.0 - - yorc-slurm-types:1.0.0 + - yorc-slurm-types:1.1.0-SNAPSHOT node_types: org.ystia.yorc.samples.job.singularity.Component: diff --git a/tosca-samples/org/ystia/yorc/samples/job/singularity/topology/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/singularity/topology/types.yaml index 501b1a74..fa618b87 100644 --- a/tosca-samples/org/ystia/yorc/samples/job/singularity/topology/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/job/singularity/topology/types.yaml @@ -26,7 +26,7 @@ description: "Slurm singularity job template1" imports: - tosca-normative-types:1.0.0-ALIEN20 - yorc-types:1.0.0 - - yorc-slurm-types:1.0.0 + - yorc-slurm-types:1.1.0-SNAPSHOT - org.ystia.yorc.samples.job.singularity.Component:1.0.0-SNAPSHOT repositories: @@ -46,7 +46,7 @@ topology_template: batch: false interfaces: tosca.interfaces.node.lifecycle.Runnable: - run: + submit: inputs: exec_command: {get_property: [SELF, exec_command]} implementation: @@ -61,7 +61,7 @@ topology_template: batch: true interfaces: tosca.interfaces.node.lifecycle.Runnable: - run: + submit: inputs: exec_command: {get_property: [SELF, exec_command]} implementation: From 4d1cfd441465df7cd1003213e5bc334a607e8d19 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Fri, 23 Nov 2018 12:00:17 +0100 Subject: [PATCH 04/19] Allow to execute slurm jobs without specific implementation --- .../src/main/resources/slurm/resources/resources.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/alien4cloud-yorc-plugin/src/main/resources/slurm/resources/resources.yaml b/alien4cloud-yorc-plugin/src/main/resources/slurm/resources/resources.yaml index c42d9de6..21248455 100644 --- a/alien4cloud-yorc-plugin/src/main/resources/slurm/resources/resources.yaml +++ b/alien4cloud-yorc-plugin/src/main/resources/slurm/resources/resources.yaml @@ -120,7 +120,9 @@ node_types: tosca.interfaces.node.lifecycle.Runnable: submit: implementation: - file: + # This is a hack to force Alien to generate this step in workflows it will be overrided in Yorc + # TODO(loicalbertin) think about use a topology modifier for this to add this step only if a submit operation exists + file: "resources.yaml" type: yorc.artifacts.Deployment.SlurmJob run: implementation: From 5aef5272b920b2015b5eead1dc988339208db940 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Mon, 26 Nov 2018 12:11:26 +0100 Subject: [PATCH 05/19] Upgrade to the latest kubernetes plugin --- pom.xml | 4 ++-- tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml | 2 +- .../org/ystia/yorc/samples/kube/containers/types.yaml | 2 +- tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml | 2 +- tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml | 2 +- .../ystia/yorc/samples/kube/topology/monitoring/types.yaml | 2 +- .../samples/kube/topology/simple-apache-emptydir/types.yaml | 2 +- .../samples/kube/topology/simple-apache-hostPath/types.yaml | 2 +- .../ystia/yorc/samples/kube/topology/simple-apache/types.yaml | 2 +- .../org/ystia/yorc/samples/kube/topology/wordpress/types.yaml | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index d7e61f3f..9a91bb86 100644 --- a/pom.xml +++ b/pom.xml @@ -25,8 +25,8 @@ - 2.1.0-SM7 - 2.1.0-SM7 + 2.1.0-SNAPSHOT + 2.1.0-SNAPSHOT 1.0.0-ALIEN20 alien_dsl_2_0_0 diff --git a/tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml index 9ddb90f0..47c14cf5 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml @@ -7,7 +7,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - - docker-types:2.1.0-SM7 + - docker-types:2.1.0-SNAPSHOT description: Apacahe Docker that can be deployed on K8S diff --git a/tosca-samples/org/ystia/yorc/samples/kube/containers/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/containers/types.yaml index 58761160..2765d09c 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/containers/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/containers/types.yaml @@ -7,7 +7,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - - docker-types:2.1.0-SM7 + - docker-types:2.1.0-SNAPSHOT description: DockerContainers that can be deployed on K8S diff --git a/tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml index 6466ab5e..bf202228 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml @@ -7,7 +7,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - - docker-types:2.1.0-SM7 + - docker-types:2.1.0-SNAPSHOT description: Grafana and graphite containers that can be deployed on K8S diff --git a/tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml index ddad6b5c..703f2189 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml @@ -7,7 +7,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - - docker-types:2.1.0-SM7 + - docker-types:2.1.0-SNAPSHOT description: Contains types for testing Jobs in Kubernetes diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/monitoring/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/monitoring/types.yaml index c97e6102..8650c485 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/monitoring/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/monitoring/types.yaml @@ -11,7 +11,7 @@ description: | imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.grafana:1.0.0-SNAPSHOT - - docker-types:2.1.0-SM7 + - docker-types:2.1.0-SNAPSHOT topology_template: node_templates: diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-emptydir/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-emptydir/types.yaml index f148c14e..4c216b15 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-emptydir/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-emptydir/types.yaml @@ -10,7 +10,7 @@ description: "Test emptyDir volumes on k8s" imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.apache:1.0.0-SNAPSHOT - - docker-types:2.1.0-SM7 + - docker-types:2.1.0-SNAPSHOT topology_template: node_templates: diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-hostPath/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-hostPath/types.yaml index 60986660..31164b50 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-hostPath/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-hostPath/types.yaml @@ -10,7 +10,7 @@ description: "Test hostPath volumes on k8s" imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.apache:1.0.0-SNAPSHOT - - docker-types:2.1.0-SM7 + - docker-types:2.1.0-SNAPSHOT topology_template: node_templates: diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache/types.yaml index eaecc75a..d432a7e3 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache/types.yaml @@ -10,7 +10,7 @@ description: "Test Apache exposed as service on k8s" imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.apache:1.0.0-SNAPSHOT - - docker-types:2.1.0-SM7 + - docker-types:2.1.0-SNAPSHOT topology_template: node_templates: diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/wordpress/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/wordpress/types.yaml index 07e48d7b..7770eb44 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/wordpress/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/wordpress/types.yaml @@ -10,7 +10,7 @@ description: "" imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.containers:1.0.0-SNAPSHOT - - docker-types:2.1.0-SM7 + - docker-types:2.1.0-SNAPSHOT topology_template: node_templates: From 135b07201f6af7f30c450d9dde46e24b82279408 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Tue, 11 Dec 2018 17:10:32 +0100 Subject: [PATCH 06/19] Added change log --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c1a5fab..1899cc74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## UNRELEASED +### ENHANCEMENTS + +* Support Jobs lifecycle enhancements (new operations `submit`, `run`, `cancel`) ([GH-196](https://github.com/ystia/yorc/issues/196)) + ## 3.1.0-M7 (December 07, 2018) ## 3.1.0-M6 (November 16, 2018) From efd0b332d61f08201c5e3cbabed7a60c56f7d120 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Wed, 12 Dec 2018 10:37:33 +0100 Subject: [PATCH 07/19] Update to a4c 2.1-RC1 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 9a91bb86..956362c2 100644 --- a/pom.xml +++ b/pom.xml @@ -21,12 +21,12 @@ alien4cloud alien4cloud-parent - 2.1.0-SM7 + 2.1.0-RC1 - 2.1.0-SNAPSHOT - 2.1.0-SNAPSHOT + 2.1.0-RC1 + 2.1.0-RC1 1.0.0-ALIEN20 alien_dsl_2_0_0 From 837609d0dab49b87ebdc70e6e4bfe6fc8f7cfa64 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Wed, 12 Dec 2018 11:29:26 +0100 Subject: [PATCH 08/19] Update samples types to a4c 2.1-RC1 --- tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml | 2 +- tosca-samples/org/ystia/yorc/samples/kube/containers/types.yaml | 2 +- tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml | 2 +- tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml | 2 +- .../org/ystia/yorc/samples/kube/topology/monitoring/types.yaml | 2 +- .../samples/kube/topology/simple-apache-emptydir/types.yaml | 2 +- .../samples/kube/topology/simple-apache-hostPath/types.yaml | 2 +- .../ystia/yorc/samples/kube/topology/simple-apache/types.yaml | 2 +- .../org/ystia/yorc/samples/kube/topology/wordpress/types.yaml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml index 47c14cf5..6cdedb5e 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/apache/types.yaml @@ -7,7 +7,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - - docker-types:2.1.0-SNAPSHOT + - docker-types:2.1.0-RC1 description: Apacahe Docker that can be deployed on K8S diff --git a/tosca-samples/org/ystia/yorc/samples/kube/containers/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/containers/types.yaml index 2765d09c..1a4444b2 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/containers/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/containers/types.yaml @@ -7,7 +7,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - - docker-types:2.1.0-SNAPSHOT + - docker-types:2.1.0-RC1 description: DockerContainers that can be deployed on K8S diff --git a/tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml index bf202228..436e2418 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/grafana/types.yaml @@ -7,7 +7,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - - docker-types:2.1.0-SNAPSHOT + - docker-types:2.1.0-RC1 description: Grafana and graphite containers that can be deployed on K8S diff --git a/tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml index 703f2189..4b3a0022 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml @@ -7,7 +7,7 @@ metadata: imports: - tosca-normative-types:1.0.0-ALIEN20 - - docker-types:2.1.0-SNAPSHOT + - docker-types:2.1.0-RC1 description: Contains types for testing Jobs in Kubernetes diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/monitoring/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/monitoring/types.yaml index 8650c485..25700588 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/monitoring/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/monitoring/types.yaml @@ -11,7 +11,7 @@ description: | imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.grafana:1.0.0-SNAPSHOT - - docker-types:2.1.0-SNAPSHOT + - docker-types:2.1.0-RC1 topology_template: node_templates: diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-emptydir/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-emptydir/types.yaml index 4c216b15..7b7a177c 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-emptydir/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-emptydir/types.yaml @@ -10,7 +10,7 @@ description: "Test emptyDir volumes on k8s" imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.apache:1.0.0-SNAPSHOT - - docker-types:2.1.0-SNAPSHOT + - docker-types:2.1.0-RC1 topology_template: node_templates: diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-hostPath/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-hostPath/types.yaml index 31164b50..008d5cb2 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-hostPath/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache-hostPath/types.yaml @@ -10,7 +10,7 @@ description: "Test hostPath volumes on k8s" imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.apache:1.0.0-SNAPSHOT - - docker-types:2.1.0-SNAPSHOT + - docker-types:2.1.0-RC1 topology_template: node_templates: diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache/types.yaml index d432a7e3..2f075a7e 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/simple-apache/types.yaml @@ -10,7 +10,7 @@ description: "Test Apache exposed as service on k8s" imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.apache:1.0.0-SNAPSHOT - - docker-types:2.1.0-SNAPSHOT + - docker-types:2.1.0-RC1 topology_template: node_templates: diff --git a/tosca-samples/org/ystia/yorc/samples/kube/topology/wordpress/types.yaml b/tosca-samples/org/ystia/yorc/samples/kube/topology/wordpress/types.yaml index 7770eb44..adfbeded 100644 --- a/tosca-samples/org/ystia/yorc/samples/kube/topology/wordpress/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/kube/topology/wordpress/types.yaml @@ -10,7 +10,7 @@ description: "" imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.kube.containers:1.0.0-SNAPSHOT - - docker-types:2.1.0-SNAPSHOT + - docker-types:2.1.0-RC1 topology_template: node_templates: From 33b34e4c423491ae19779246dffe0fae6a88d133 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Thu, 13 Dec 2018 10:38:52 +0100 Subject: [PATCH 09/19] Update Singularity samples to make them more usable in different context That said, they are still very specific to our setup --- .../yorc/samples/job/singularity/component/types.yaml | 8 ++++++++ .../yorc/samples/job/singularity/topology/types.yaml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tosca-samples/org/ystia/yorc/samples/job/singularity/component/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/singularity/component/types.yaml index ff079488..b7e39f58 100644 --- a/tosca-samples/org/ystia/yorc/samples/job/singularity/component/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/job/singularity/component/types.yaml @@ -26,6 +26,14 @@ imports: - yorc-types:1.0.0 - yorc-slurm-types:1.1.0-SNAPSHOT +repositories: + docker: + url: https://hpda-docker-registry:5000/ + type: a4c_ignore + cluster_nfs: + url: not used + type: a4c_ignore + node_types: org.ystia.yorc.samples.job.singularity.Component: derived_from: yorc.nodes.slurm.SingularityJob diff --git a/tosca-samples/org/ystia/yorc/samples/job/singularity/topology/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/singularity/topology/types.yaml index fa618b87..f0907543 100644 --- a/tosca-samples/org/ystia/yorc/samples/job/singularity/topology/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/job/singularity/topology/types.yaml @@ -65,6 +65,6 @@ topology_template: inputs: exec_command: {get_property: [SELF, exec_command]} implementation: - file: /home_nfs/benoists/hello-world.img + file: /home_nfs/commons/hello-world.img repository: cluster_nfs type: yorc.artifacts.Deployment.SlurmJobImage From b07d4583b6dfa3948bfb09abda6aac7c4c278369 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Thu, 13 Dec 2018 15:13:30 +0100 Subject: [PATCH 10/19] Added a mock component to test Jobs --- .../job/mocks/component/scripts/cancel.sh | 3 + .../job/mocks/component/scripts/run.sh | 34 ++++++++++++ .../job/mocks/component/scripts/submit.sh | 5 ++ .../samples/job/mocks/component/types.yaml | 55 +++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/cancel.sh create mode 100644 tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/run.sh create mode 100644 tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/submit.sh create mode 100644 tosca-samples/org/ystia/yorc/samples/job/mocks/component/types.yaml diff --git a/tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/cancel.sh b/tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/cancel.sh new file mode 100644 index 00000000..bac409e8 --- /dev/null +++ b/tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/cancel.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo "Job: ${TOSCA_JOB_ID} cancelled..." diff --git a/tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/run.sh b/tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/run.sh new file mode 100644 index 00000000..8232d181 --- /dev/null +++ b/tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/run.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +echo "Checking status for job ${TOSCA_JOB_ID}" +echo "First, let sleep for ${DELAY} seconds..." +sleep ${DELAY} + +TOSCA_JOB_STATUS="COMPLETED" + +if [[ "${FAILURE}" == "true" ]] ; then + TOSCA_JOB_STATUS="FAILED" +fi + +if [[ "${RANDOM_STATUS}" == "true" ]] ; then + mod=3 + if [[ "${FAILURE}" == "true" ]] ; then + mod=4 + fi + case $(( ${RANDOM} % ${mod} )) in + 2) + TOSCA_JOB_STATUS="COMPLETED" + ;; + 3) + # May happen only if mod=4 + TOSCA_JOB_STATUS="FAILED" + ;; + *) + TOSCA_JOB_STATUS="RUNNING" + ;; + esac +fi + +echo "Computed job status is: ${TOSCA_JOB_STATUS}" + +export TOSCA_JOB_STATUS \ No newline at end of file diff --git a/tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/submit.sh b/tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/submit.sh new file mode 100644 index 00000000..bb9bbb76 --- /dev/null +++ b/tosca-samples/org/ystia/yorc/samples/job/mocks/component/scripts/submit.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +echo "Submitting job..." +export TOSCA_JOB_ID="Job-${RANDOM}" +echo "Let say that job id is: ${TOSCA_JOB_ID} (we are a mock anyway...)" diff --git a/tosca-samples/org/ystia/yorc/samples/job/mocks/component/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/mocks/component/types.yaml new file mode 100644 index 00000000..b733f6b3 --- /dev/null +++ b/tosca-samples/org/ystia/yorc/samples/job/mocks/component/types.yaml @@ -0,0 +1,55 @@ +tosca_definitions_version: alien_dsl_2_0_0 +# +# Copyright 2018 Bull S.A.S. Atos Technologies - Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois, France. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +metadata: + template_name: org.ystia.yorc.samples.job.mocks.Component + template_version: 1.0.0-SNAPSHOT + template_author: yorc + +imports: + - tosca-normative-types:1.0.0-ALIEN20 + +node_types: + org.ystia.yorc.samples.job.mocks.DelayJob: + derived_from: tosca.nodes.Root + properties: + run_delay: + type: integer + default: 3 + required: false + constraints: + - greater_or_equal: 0 + random_status: + type: boolean + default: false + required: false + failure: + type: boolean + default: false + description: if both failure and random_status are true a fail become one of the possible status with running and done + required: false + interfaces: + tosca.interfaces.node.lifecycle.Runnable: + submit: scripts/submit.sh + run: + inputs: + DELAY: { get_property: [SELF, run_delay]} + RANDOM_STATUS: { get_property: [SELF, random_status]} + FAILURE: { get_property: [SELF, failure]} + implementation: scripts/run.sh + cancel: scripts/cancel.sh \ No newline at end of file From 1553fb8405bbacdcd9bd6b1736d5c2f152e7fd0d Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Thu, 13 Dec 2018 16:13:35 +0100 Subject: [PATCH 11/19] Create topologies for Kubernetes Jobs Also moved kubernetes Jobs components --- .../jobs => job/k8s/components}/types.yaml | 0 .../job/k8s/topologies/compute_pi/types.yaml | 54 +++++++++++++++++++ .../job/k8s/topologies/fail/types.yaml | 53 ++++++++++++++++++ .../job/k8s/topologies/loop/types.yaml | 53 ++++++++++++++++++ 4 files changed, 160 insertions(+) rename tosca-samples/org/ystia/yorc/samples/{kube/jobs => job/k8s/components}/types.yaml (100%) create mode 100644 tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/compute_pi/types.yaml create mode 100644 tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/fail/types.yaml create mode 100644 tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/loop/types.yaml diff --git a/tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/k8s/components/types.yaml similarity index 100% rename from tosca-samples/org/ystia/yorc/samples/kube/jobs/types.yaml rename to tosca-samples/org/ystia/yorc/samples/job/k8s/components/types.yaml diff --git a/tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/compute_pi/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/compute_pi/types.yaml new file mode 100644 index 00000000..0f38e9a4 --- /dev/null +++ b/tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/compute_pi/types.yaml @@ -0,0 +1,54 @@ +tosca_definitions_version: alien_dsl_2_0_0 + +metadata: + template_name: KubeJobPi + template_version: 0.1.0-SNAPSHOT + template_author: admin + +description: "" + +imports: + - tosca-normative-types:1.0.0-ALIEN20 + - docker-types:2.1.0-RC1 + - org.ystia.yorc.samples.kube.jobs:1.0.0-SNAPSHOT + +topology_template: + node_templates: + ContainerJobUnit: + metadata: + a4c_edit_x: 111 + a4c_edit_y: "-53" + type: org.alien4cloud.extended.container.types.ContainerJobUnit + ContainerRuntime: + type: org.alien4cloud.extended.container.types.ContainerRuntime + requirements: + - hostedOnContainerJobUnitHost: + type_requirement: host + node: ContainerJobUnit + capability: tosca.capabilities.Container.Docker + relationship: tosca.relationships.HostedOn + ComputePIJob: + type: org.ystia.yorc.samples.kube.containers.nodes.ComputePIJob + properties: + docker_run_cmd: + - perl + - "-Mbignum=bpi" + - "-wle" + - "print bpi(2000)" + cpu_share: 1.0 + mem_share: "128 MB" + docker_bash_cmd: + - "/bin/bash" + - "-c" + requirements: + - hostedOnContainerRuntimeContainerRuntimeHost: + type_requirement: host + node: ContainerRuntime + capability: org.alien4cloud.extended.container.capabilities.ApplicationHost + relationship: org.alien4cloud.extended.container.relationships.HostedOnContainerRuntime + capabilities: + scalable: + properties: + min_instances: 1 + max_instances: 1 + default_instances: 1 diff --git a/tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/fail/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/fail/types.yaml new file mode 100644 index 00000000..7d110f51 --- /dev/null +++ b/tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/fail/types.yaml @@ -0,0 +1,53 @@ +tosca_definitions_version: alien_dsl_2_0_0 + +metadata: + template_name: KubeJobFail + template_version: 0.1.0-SNAPSHOT + template_author: admin + +description: "" + +imports: + - tosca-normative-types:1.0.0-ALIEN20 + - docker-types:2.1.0-RC1 + - org.ystia.yorc.samples.kube.jobs:1.0.0-SNAPSHOT + +topology_template: + node_templates: + ContainerJobUnit: + metadata: + a4c_edit_x: 130 + a4c_edit_y: "-19" + type: org.alien4cloud.extended.container.types.ContainerJobUnit + ContainerRuntime: + type: org.alien4cloud.extended.container.types.ContainerRuntime + requirements: + - hostedOnContainerJobUnitHost: + type_requirement: host + node: ContainerJobUnit + capability: tosca.capabilities.Container.Docker + relationship: tosca.relationships.HostedOn + ComputeFail: + type: org.ystia.yorc.samples.kube.containers.nodes.ComputeFail + properties: + docker_run_cmd: + - "/bin/bash" + - "-c" + - "sleep 10; >&2 echo 'Computation Failed!'; exit 1" + cpu_share: 1.0 + mem_share: "128 MB" + docker_bash_cmd: + - "/bin/bash" + - "-c" + requirements: + - hostedOnContainerRuntimeContainerRuntimeHost: + type_requirement: host + node: ContainerRuntime + capability: org.alien4cloud.extended.container.capabilities.ApplicationHost + relationship: org.alien4cloud.extended.container.relationships.HostedOnContainerRuntime + capabilities: + scalable: + properties: + min_instances: 1 + max_instances: 1 + default_instances: 1 diff --git a/tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/loop/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/loop/types.yaml new file mode 100644 index 00000000..69c3adc4 --- /dev/null +++ b/tosca-samples/org/ystia/yorc/samples/job/k8s/topologies/loop/types.yaml @@ -0,0 +1,53 @@ +tosca_definitions_version: alien_dsl_2_0_0 + +metadata: + template_name: KubeJobLoop + template_version: 0.1.0-SNAPSHOT + template_author: admin + +description: "" + +imports: + - tosca-normative-types:1.0.0-ALIEN20 + - docker-types:2.1.0-RC1 + - org.ystia.yorc.samples.kube.jobs:1.0.0-SNAPSHOT + +topology_template: + node_templates: + ContainerJobUnit: + metadata: + a4c_edit_x: 174 + a4c_edit_y: "-90" + type: org.alien4cloud.extended.container.types.ContainerJobUnit + ContainerRuntime: + type: org.alien4cloud.extended.container.types.ContainerRuntime + requirements: + - hostedOnContainerJobUnitHost: + type_requirement: host + node: ContainerJobUnit + capability: tosca.capabilities.Container.Docker + relationship: tosca.relationships.HostedOn + ComputeBashLoop: + type: org.ystia.yorc.samples.kube.containers.nodes.ComputeBashLoop + properties: + docker_run_cmd: + - "/bin/bash" + - "-c" + - "for d in $(seq 1 15); do echo $d; sleep $d; done; echo 'Computation done!';" + cpu_share: 1.0 + mem_share: "128 MB" + docker_bash_cmd: + - "/bin/bash" + - "-c" + requirements: + - hostedOnContainerRuntimeContainerRuntimeHost: + type_requirement: host + node: ContainerRuntime + capability: org.alien4cloud.extended.container.capabilities.ApplicationHost + relationship: org.alien4cloud.extended.container.relationships.HostedOnContainerRuntime + capabilities: + scalable: + properties: + min_instances: 1 + max_instances: 1 + default_instances: 1 From 23e7e92bde4a4adf72901d975508a0f4870ed2dd Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Fri, 14 Dec 2018 15:03:41 +0100 Subject: [PATCH 12/19] Update slurm types --- .../org/ystia/yorc/samples/job/srun/topology/types.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tosca-samples/org/ystia/yorc/samples/job/srun/topology/types.yaml b/tosca-samples/org/ystia/yorc/samples/job/srun/topology/types.yaml index 3509dd90..26921c36 100644 --- a/tosca-samples/org/ystia/yorc/samples/job/srun/topology/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/job/srun/topology/types.yaml @@ -25,7 +25,7 @@ imports: - tosca-normative-types:1.0.0-ALIEN20 - org.ystia.yorc.samples.job.srun.Component:1.0.0-SNAPSHOT - yorc-types:1.0.0 - - yorc-slurm-types:1.0.0 + - yorc-slurm-types:1.1.0-SNAPSHOT topology_template: node_templates: From 4f01c7c79b0c4548a98b812a58c563b4bfff3d64 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Fri, 14 Dec 2018 15:06:29 +0100 Subject: [PATCH 13/19] Make vision types snapshots otherwise we can't reimport them --- .../org/ystia/yorc/samples/vision/linux/ansible/types.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tosca-samples/org/ystia/yorc/samples/vision/linux/ansible/types.yaml b/tosca-samples/org/ystia/yorc/samples/vision/linux/ansible/types.yaml index d5ba4bfd..136c41b8 100644 --- a/tosca-samples/org/ystia/yorc/samples/vision/linux/ansible/types.yaml +++ b/tosca-samples/org/ystia/yorc/samples/vision/linux/ansible/types.yaml @@ -18,7 +18,7 @@ tosca_definitions_version: alien_dsl_2_0_0 metadata: template_name: org.ystia.yorc.samples.vision.linux.ansible - template_version: 1.0.0 + template_version: 1.0.0-SNAPSHOT template_author: yorc imports: From 304b3d37129c9c81aeac6ed535288906f2b0e963 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Mon, 17 Dec 2018 09:41:24 +0100 Subject: [PATCH 14/19] Fix sbatch sample README --- .../ystia/yorc/samples/job/sbatch/README.md | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/tosca-samples/org/ystia/yorc/samples/job/sbatch/README.md b/tosca-samples/org/ystia/yorc/samples/job/sbatch/README.md index 150e473d..2b47c52a 100644 --- a/tosca-samples/org/ystia/yorc/samples/job/sbatch/README.md +++ b/tosca-samples/org/ystia/yorc/samples/job/sbatch/README.md @@ -13,7 +13,7 @@ Given the following TOSCA operation definition: ```yaml interfaces: tosca.interfaces.node.lifecycle.Runnable: - run: + submit: implementation: file: bin/submit.sh type: yorc.artifacts.Deployment.SlurmJobBin @@ -22,8 +22,7 @@ Given the following TOSCA operation definition: A SBATCH script needs to be provided. The implementation type must be `yorc.artifacts.Deployment.SlurmJobBin`. - -## Outputs & logging +## Outputs & logging The program is 30s delayed in order to allow retrieving job information as JobID and job state. This information will appear periodically in the Yorc/Alien logs: @@ -31,20 +30,22 @@ This information will appear periodically in the Yorc/Alien logs: When the program will be run, the following messages will appear in Yorc/Alien logs, in function of the tasks and nodes job properties and in the res_mpi.out file: -`First srun - Hello john! I am process number: 1 on host hpda16 - Hello john! I am process number: 0 on host hpda16 - Hello john! I am process number: 2 on host hpda16 - Hello john! I am process number: 3 on host hpda16 - Second srun - Hello mary! I am process number: 0 on host hpda16 - Hello mary! I am process number: 1 on host hpda16 - Hello mary! I am process number: 2 on host hpda16 - Hello mary! I am process number: 3 on host hpda16 - Third srun - Hello fred! I am process number: 0 on host hpda16 - Hello fred! I am process number: 1 on host hpda16 - Hello fred! I am process number: 2 on host hpda16 - Hello fred! I am process number: 3 on host hpda16` - -The output files are saved in a root home user directory with name "job__outputs" \ No newline at end of file +``` +First srun +Hello john! I am process number: 1 on host hpda16 +Hello john! I am process number: 0 on host hpda16 +Hello john! I am process number: 2 on host hpda16 +Hello john! I am process number: 3 on host hpda16 +Second srun +Hello mary! I am process number: 0 on host hpda16 +Hello mary! I am process number: 1 on host hpda16 +Hello mary! I am process number: 2 on host hpda16 +Hello mary! I am process number: 3 on host hpda16 +Third srun +Hello fred! I am process number: 0 on host hpda16 +Hello fred! I am process number: 1 on host hpda16 +Hello fred! I am process number: 2 on host hpda16 +Hello fred! I am process number: 3 on host hpda16 +``` + +The output files are saved in a root home user directory with name `job__outputs` \ No newline at end of file From a14d8bb3ed24f9651d0b3e54da587527684aa471 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Mon, 17 Dec 2018 11:55:50 +0100 Subject: [PATCH 15/19] Document Jobs --- .../_static/img/JobsRunLifeCycle.png | Bin 0 -> 31072 bytes documentation/conf.py | 4 +- documentation/index.rst | 1 + documentation/jobs.rst | 124 ++++++++++++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 documentation/_static/img/JobsRunLifeCycle.png create mode 100644 documentation/jobs.rst diff --git a/documentation/_static/img/JobsRunLifeCycle.png b/documentation/_static/img/JobsRunLifeCycle.png new file mode 100644 index 0000000000000000000000000000000000000000..2e66a5bf2f494a9ca1dd57ab8411993e4d61ab3e GIT binary patch literal 31072 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�dd?22N6s$BWic>Vgw9FBoPbdp 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 literal 0 HcmV?d00001 diff --git a/documentation/conf.py b/documentation/conf.py index 01225ae6..da54ebe6 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -66,7 +66,7 @@ # General information about the project. project = u'Alien4Cloud Yorc Plugin' -copyright = u'2017, Atos BDS R&D' +copyright = u'2017-2018, Atos BDS R&D' author = u'Atos BDS R&D' # The version info for the project you're documenting, acts as replacement for @@ -121,7 +121,7 @@ #keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = True +todo_include_todos = False # -- Options for HTML output ---------------------------------------------- diff --git a/documentation/index.rst b/documentation/index.rst index 2d7cf038..c5f67fb9 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -32,5 +32,6 @@ Contents: location quickstart upgrade + jobs diff --git a/documentation/jobs.rst b/documentation/jobs.rst new file mode 100644 index 00000000..2e6f4b23 --- /dev/null +++ b/documentation/jobs.rst @@ -0,0 +1,124 @@ +.. + Copyright 2018 Bull S.A.S. Atos Technologies - Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois, France. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --- + +Working with Jobs +================= + +What's a Job? +------------- + +By opposite to a service which is a long running application, a Job is an +application that runs to completion. + +TOSCA life-cycle (install -> configure -> start ....... then finally stop +-> delete) was designed to handle services. +There is no concept of Jobs life-cycle within normative TOSCA. + +But, as per our experience in HPC and emerging container scheduling +within Container as a Service solutions like Kubernetes, we are convinced +that supporting Job scheduling is fundamental for any orchestration solution. + +So we decided in collaboration with the Alien4Cloud team to extend TOSCA to +support Jobs! + +Extending TOSCA to support Jobs +------------------------------- + +First was the life-cycle! In TOSCA the core concept is the life-cycle. So, +based on our experience we defined a life-cycle for Jobs. + +.. image:: _static/img/JobsRunLifeCycle.png + :alt: Jobs Life Cycle + :align: center + +Translated in TOSCA, we defined a new interface +``tosca.interfaces.node.lifecycle.Runnable`` this interface defines three +operations: + +* ``submit``: Submit is this operation that *submits* a job to a Job Scheduler, + generally at the end of the ``submit`` we got a **job identifier** +* ``run``: Run is an asynchronous operation that will be called periodically + to check the **job status**. +* ``cancel``: Cancel allows to *cancels* a **submitted job**. + +Supported Jobs Schedulers +------------------------- + +Slurm +~~~~~ + +Slurm is an HPC scheduler. Unsurprisingly, it was our first builtin support for +Jobs scheduling. Our Slurm support allows run single jobs and batches made of +several jobs. + +.. todo:: Include a description on how to write SlurmBin/SlurmBatch/Singularity + Jobs + +Kubernetes +~~~~~~~~~~ + +Over the years Kubernetes became the de-facto standard of Containers As A +Service (CaaS). + +Kubernetes has a special builtin *Controller* for jobs called *Jobs - Run to +Completion*. + +.. todo:: Include a description on how to write Kubernetes Jobs + +The one you want! +~~~~~~~~~~~~~~~~~ + +Yorc also support Jobs defined in pure-TOSCA. That means that you are able +to write using YAML and Python, Shell or Ansible scripts your own interaction +with any scheduler. + +All you need to do is to provide implementation for at least the ``submit`` +operation of the job life-cycle. If you do not provide implementation for +the ``run`` operation, your job will run in *fire and forget* mode, you will +not be able to get information about its completion. Similarly, if you do not +provide an implementation for the ``cancel`` operation then your Job will +simply not being cancellable. + +To allow Yorc to manage your job properly some conventions: + +* at the end of the ``submit`` operation you should export a fact or + environment variable named ``TOSCA_JOB_ID`` containing the + **submitted job identifier**. + +* Yorc automatically injects this ``TOSCA_JOB_ID`` as an input of the ``run`` + and ``cancel`` operations. + +* The ``run`` operation should be designed to be **non-blocking** and + **called several times**. Its primary role is to check the job status. It + should export a fact or environment variable named ``TOSCA_JOB_STATUS`` + containing one of the following values: + + * ``COMPLETED``: meaning that the job is done successfully. + * ``FAILED``: meaning that the job is done but in error. + * ``RUNNING``: meaning that the job is still running. + * ``QUEUED``: meaning that the job is submitted but didn't started yet. + + Internally ``RUNNING`` and ``QUEUED`` statuses are handled the same way by + Yorc that will recall the ``run`` operation after a delay to refresh the + status. + +* The ``run`` operation can also be used to retrieve logs or perform some + cleanup after the job completion. + + +You can find an example of a pure-TOSCA implementation of jobs in the official +*CSARs public library* with an implementation of a +`Spark Job `_ From 2ac0a7e835431e96c725192e9dd2e2d434e8f0a3 Mon Sep 17 00:00:00 2001 From: Laurent Ganne <33217305+laurentganne@users.noreply.github.com> Date: Mon, 17 Dec 2018 12:02:32 +0100 Subject: [PATCH 16/19] minor typo --- documentation/jobs.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/jobs.rst b/documentation/jobs.rst index 2e6f4b23..eb6d582c 100644 --- a/documentation/jobs.rst +++ b/documentation/jobs.rst @@ -52,7 +52,7 @@ operations: generally at the end of the ``submit`` we got a **job identifier** * ``run``: Run is an asynchronous operation that will be called periodically to check the **job status**. -* ``cancel``: Cancel allows to *cancels* a **submitted job**. +* ``cancel``: Cancel allows to *cancel* a **submitted job**. Supported Jobs Schedulers ------------------------- @@ -61,7 +61,7 @@ Slurm ~~~~~ Slurm is an HPC scheduler. Unsurprisingly, it was our first builtin support for -Jobs scheduling. Our Slurm support allows run single jobs and batches made of +Jobs scheduling. Our Slurm support allows to run single jobs and batches made of several jobs. .. todo:: Include a description on how to write SlurmBin/SlurmBatch/Singularity From 6b296f7ef0df526a34b5ebefd8771f8738adafa5 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Mon, 17 Dec 2018 12:21:37 +0100 Subject: [PATCH 17/19] Document builtin jobs workflows and cancellation --- documentation/jobs.rst | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/documentation/jobs.rst b/documentation/jobs.rst index 2e6f4b23..d33c2a55 100644 --- a/documentation/jobs.rst +++ b/documentation/jobs.rst @@ -122,3 +122,36 @@ To allow Yorc to manage your job properly some conventions: You can find an example of a pure-TOSCA implementation of jobs in the official *CSARs public library* with an implementation of a `Spark Job `_ + +Specific workflows for Jobs +--------------------------- + +When your application contains Jobs (meaning node templates which implements +the ``tosca.interfaces.node.lifecycle.Runnable`` interface) then Alien4Cloud +will automatically generate two workflows: + +* ``run``: a workflow that submits and monitor jobs +* ``cancel``: a workflow that cancels jobs + +.. warning:: The cancel workflow is a kind of temporary work around. It allows + to cancel jobs but do not take care if the job is submitted or not. The + recommended way to cancel a ``run`` workflow is to cancel the associated + task in Yorc using either the CLI or the Rest API. + This is temporary and we will provide soon a way to cancel workflows directly + from Alien4Cloud. + +The ``run`` workflow allows to orchestrate Jobs. That means that if for +instance, ``jobB`` depends on ``jobA`` using a TOSCA ``dependsOn`` or +``connectsTO`` relationship then Alien4Cloud will generate a workflow that +first submit and wait for the completion of ``jobA`` before submitting +``jobB``. + +Jobs cancellation +----------------- + +The proper way to cancel Jobs that were submitted by a TOSCA workflow is +to cancel the associated Yorc Task/Execution of this workflow. +This way Yorc will automatically call ``cancel`` operations for nodes that +implement it and which have successfully executed their ``submit`` operation. +Currently those automatic cancellation steps do not appear in Alien4Cloud. +We will work soon on making them visible. From d1e741d3e52957c1bdf43915c1f3a5f965833361 Mon Sep 17 00:00:00 2001 From: stephane benoist <29753229+stebenoist@users.noreply.github.com> Date: Mon, 17 Dec 2018 16:44:15 +0100 Subject: [PATCH 18/19] Set deployment status when failure has been received from status event --- .../java/org/ystia/yorc/alien4cloud/plugin/DeployTask.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/DeployTask.java b/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/DeployTask.java index 76a7933e..6a62672d 100644 --- a/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/DeployTask.java +++ b/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/DeployTask.java @@ -225,6 +225,10 @@ public void run() { orchestrator.changeStatus(paasId, DeploymentStatus.DEPLOYED); done = true; break; + case "DEPLOYMENT_FAILED": + orchestrator.doChangeStatus(paasId, DeploymentStatus.FAILURE); + error = new Exception("Deployment failed"); + break; default: log.debug("Deployment Status is currently " + status); break; From 9592bc914a5e52ac2aa63fe1ebcf9987da217d43 Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Mon, 17 Dec 2018 17:48:44 +0100 Subject: [PATCH 19/19] Fix deployments events consuming was overloaded by workflow events --- .../alien4cloud/plugin/EventListenerTask.java | 3 - .../yorc/alien4cloud/plugin/WorkflowTask.java | 76 ++----------------- 2 files changed, 7 insertions(+), 72 deletions(-) diff --git a/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/EventListenerTask.java b/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/EventListenerTask.java index 8937f247..50c91ceb 100644 --- a/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/EventListenerTask.java +++ b/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/EventListenerTask.java @@ -158,7 +158,6 @@ public void run() { eMessage += event.getType() + ":" + eState; log.debug("Received Event from Yorc <<< " + eMessage); synchronized (jrdi) { - jrdi.setLastEvent(event); jrdi.notifyAll(); } switch (event.getStatus()) { @@ -190,7 +189,6 @@ public void run() { eMessage += event.getType() + ":" + eState; log.debug("Received Event from Yorc <<< " + eMessage); synchronized (jrdi) { - jrdi.setLastEvent(event); jrdi.notifyAll(); } switch (event.getStatus()) { @@ -215,7 +213,6 @@ public void run() { eMessage += event.getType() + ":" + eState; log.debug("Received Event from Yorc <<< " + eMessage); synchronized (jrdi) { - jrdi.setLastEvent(event); jrdi.notifyAll(); } switch (event.getStatus()) { diff --git a/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/WorkflowTask.java b/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/WorkflowTask.java index 49e86a57..62b18975 100644 --- a/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/WorkflowTask.java +++ b/alien4cloud-yorc-plugin/src/main/java/org/ystia/yorc/alien4cloud/plugin/WorkflowTask.java @@ -72,82 +72,20 @@ public void run() { Event evt; while (!done && error == null) { synchronized (jrdi) { - // Check for timeout + // Check deployment timeout long timetowait = timeout - System.currentTimeMillis(); if (timetowait <= 0) { - log.warn("Timeout occured"); - error = new Throwable("Workflow timeout"); + log.warn("Deployment Timeout occured"); + error = new Throwable("Deployment timeout"); + orchestrator.doChangeStatus(paasId, DeploymentStatus.FAILURE); break; } - // Wait Events from Yorc - log.debug(paasId + ": Waiting for workflow events."); + // Wait Deployment Events from Yorc + log.debug(paasId + ": Waiting for deployment events."); try { jrdi.wait(timetowait); } catch (InterruptedException e) { - log.error("Interrupted while waiting for task end"); - break; - } - // Check if we received a Workflow Event and process it - evt = jrdi.getLastEvent(); - if (evt != null && evt.getAlienExecutionId().equals(taskId)) { - jrdi.setLastEvent(null); - switch (evt.getType()) { - case EventListenerTask.EVT_WORKFLOW: - switch (evt.getStatus()) { - case "failed": - log.warn("Workflow failed: " + paasId); - orchestrator.postWorkflowMonitorEvent(new PaaSWorkflowFailedEvent(), evt); - error = new Exception("Workflow " + workflowName + " failed"); - break; - case "canceled": - log.warn("Workflow canceled: " + paasId); - orchestrator.postWorkflowMonitorEvent(new PaaSWorkflowCancelledEvent(), evt); - error = new Exception("Workflow " + workflowName + " canceled"); - break; - case "done": - orchestrator.postWorkflowMonitorEvent(new PaaSWorkflowSucceededEvent(), evt); - done = true; - break; - case "initial": - orchestrator.postWorkflowMonitorEvent(new PaaSWorkflowStartedEvent(), evt); - break; - default: - log.warn("An event has been ignored. Unexpected status=" + evt.getStatus()); - break; - } - break; - case EventListenerTask.EVT_WORKFLOW_STEP: - switch (evt.getStatus()) { - case "initial": - orchestrator.postWorkflowStepEvent(new WorkflowStepStartedEvent(), evt); - break; - case "done": - case "error": - orchestrator.postWorkflowStepEvent(new WorkflowStepCompletedEvent(), evt); - break; - } - break; - case EventListenerTask.EVT_ALIEN_TASK: - switch (evt.getStatus()) { - case "initial": - orchestrator.postTaskEvent(new TaskSentEvent(), evt); - break; - case "running": - orchestrator.postTaskEvent(new TaskStartedEvent(), evt); - break; - case "done": - orchestrator.postTaskEvent(new TaskSucceededEvent(), evt); - break; - case "error": - orchestrator.postTaskEvent(new TaskFailedEvent(), evt); - break; - case "canceled": - orchestrator.postTaskEvent(new TaskCancelledEvent(), evt); - break; - } - break; - } - continue; + log.warn("Interrupted while waiting for deployment"); } } // We were awaken for some bad reason or a timeout