diff --git a/automatique.env.yaml.example b/automatique.env.yaml.example
new file mode 100644
index 0000000..b8ea706
--- /dev/null
+++ b/automatique.env.yaml.example
@@ -0,0 +1,272 @@
+vnf-lcm:
+ mtas-41-vnflcm: &mtas-41-vnflcm
+ ssh-alias: mtas-41-vnflcm
+ socks-proxy: localhost:1081
+ storage: cinder
+ address: 10.80.84.14
+ user: cloud-user
+ mtas-55-vnflcm: &mtas-55-vnflcm
+ ssh-alias: mtas-55-vnflcm
+ socks-proxy: localhost:1081
+ storage: ephemeral
+ address: 10.80.99.142
+ user: cloud-user
+
+vim:
+ mtas-41-atlas: &mtas-41-atlas
+ ssh-alias: mtas-41-atlas
+ type: openstack
+ storage: cinder
+ address: 10.80.84.20
+ user: atlasadm
+ mtas-55-atlas: &mtas-55-atlas
+ ssh-alias: mtas-55-atlas
+ type: openstack
+ storage: ephemeral
+ address: 10.80.99.148
+ user: atlasadm
+
+node:
+ mtas-41-1:
+ vim: *mtas-41-atlas
+ vnf-lcm: *mtas-41-vnflcm
+ project: MTAS-41-1
+ openrc: openrc-41-1
+ template-params:
+ legacy:
+ -p: "profile1"
+ -s: "cinder"
+# -v: "ipv4"
+ -v: "dualstack"
+ -n: "VLAN"
+ -b: "True"
+ jinja:
+ internal_network: one_int_net
+ vip_fe_network_number: 3
+# ip_version: ipv4
+ ip_version: ipv4ipv6
+ local_disk_realization: cinder-volume
+ ha_policy: none
+ network_type: VLAN
+ maximum_number_of_PLs: 10
+ port_security_vip_external: disable
+ port_security_non_vip_external: disable
+ wait_handler: disable
+ env:
+ shared:
+ availability_zone: {'*':mtas}
+ VM_HA_policy_SC: managed-on-host
+ VM_HA_policy_PL: ha-offline
+ VM_image_PL: CXP9028685_1-R3A
+ SC-1_SC-2_cinder_volume_size: 50
+ number_of_scaled_out_VMs: 0
+ VM_to_be_scaled_in: []
+ nw_internal_mtu: 1500
+ OM_IPv4_address: 10.80.103.12
+ SC-1_IPv4_address: 10.80.103.13
+ SC-2_IPv4_address: 10.80.103.14
+ OM_IPv6_address: 2001:1b70:8294:3d61::4
+ SC-1_IPv6_address: 2001:1b70:8294:3d61::5
+ SC-2_IPv6_address: 2001:1b70:8294:3d61::6
+ DNS_server_1_address: 10.51.40.100
+ DNS_server_2_address: 10.51.40.101
+ DNS_server_3_address: 10.64.73.100
+ DNS_server_4_address: 10.64.73.101
+ NTP_server_1_address: 10.51.40.102
+ NTP_server_2_address: 10.51.40.103
+ NTP_server_3_address: 10.64.73.102
+ NTP_server_4_address: 10.64.73.103
+ defaultURI: none
+ defaultSecURI: none
+ time_zone: Europe/Stockholm
+ watchdog_timeout: 30
+ interval_timeout: 10
+ shutdown_timeout: 600
+ platform-vip: 10.80.103.128
+ platform-vip6: 2001:1b70:8294:3d00::4110
+ tasvip4: 10.80.103.129
+ tasvip6: 2001:1b70:8294:3d00::4111
+ ut-vip4: 10.80.103.130
+ ut-vip6: 2001:1b70:8294:3d00::4112
+ cai3g-vip4: 10.80.103.131
+ cai3g-vip6: 2001:1b70:8294:3d00::4113
+ sigtran1-vip4: 10.80.103.132
+ sigtran1-vip6: 2001:1b70:8294:3d00::4114
+ sigtran2-vip4: 10.80.103.133
+ sigtran2-vip6: 2001:1b70:8294:3d00::4115
+ emergency_username: maintenance
+ emergency_password_hash: $6$Kjfq3r8jjaVG$A9/prKfLo9a4TKTaGSyDdk0rxk24IuoGr1SXmj.LTu81Ev9eZ8FBDjow7TEgNb.4t2i8w2LDF/R/VuIKknpLk0
+ secla_password_hash: $6$Kjfq3r8jjaVG$A9/prKfLo9a4TKTaGSyDdk0rxk24IuoGr1SXmj.LTu81Ev9eZ8FBDjow7TEgNb.4t2i8w2LDF/R/VuIKknpLk0
+ root_password_hash: $6$Kjfq3r8jjaVG$A9/prKfLo9a4TKTaGSyDdk0rxk24IuoGr1SXmj.LTu81Ev9eZ8FBDjow7TEgNb.4t2i8w2LDF/R/VuIKknpLk0
+ oss_pm_password_hash: $6$Kjfq3r8jjaVG$A9/prKfLo9a4TKTaGSyDdk0rxk24IuoGr1SXmj.LTu81Ev9eZ8FBDjow7TEgNb.4t2i8w2LDF/R/VuIKknpLk0
+ DbnVMSharedMemoryPercentage: 37
+ DbnVMRecordHeapPercentage: 80
+ MultiMMapMaxMem: 32
+ jvm_initial_heap_size_Xms: 768m
+ jvm_initial_heap_size_eden_Xmn: 512m
+ jvm_max_heap_size_Xmx: 1536m
+ internal_net_mtu: 1500
+ mtu_cache_refresh_timer: 600
+ legacy:
+ # VM_flavor: vMTAS_16-54
+ VM_flavor: vMTAS_4-27
+ VM_image_SC: MTASv_4_CXP9031366-R19E05
+ VM_image_SC_1: MTASv_4_CXP9031366-R19E05
+ VM_image_SC_2: MTASv_4_CXP9031366-R19E05
+ om_sp1_net_name: mtas-41-1-nw_om_sp1
+ om_sp1_net_mtu: 1500
+ om_sp1_subnet_IPv4_name: mtas-41-1-nw_om_sp1_subnet_IPv4
+ om_sp1_subnet_IPv4_address: 10.80.103.8/29
+ om_sp1_subnet_IPv4_gateway_address: 10.80.103.9
+ om_sp1_subnet_IPv6_name: mtas-41-1-nw_om_sp1_subnet_IPv6
+ om_sp1_subnet_IPv6_address: 2001:1b70:8294:3d61::/64
+ om_sp1_subnet_IPv6_gateway_address: fe80::10:80:103:9
+ om_sp2_net_name: mtas-41-1-nw_om_sp2
+ om_sp2_net_mtu: 1500
+ sig_sp_net_name: mtas-41-1-nw_sig_sp
+ sig_sp_net_mtu: 1500
+ bar_sp_net_name: mtas-41-1-nw_bar_sp
+ bar_sp_net_mtu: 1500
+ jinja:
+ # VM_flavor_SC: vMTAS_16-54
+ # VM_flavor_PL: vMTAS_16-54
+ VM_flavor_SC: vMTAS_4-27
+ VM_flavor_PL: vMTAS_4-27
+ VM_image_SC: MTASv_4_CXP9031366-R19E05
+ VM_image_SC-1: MTASv_4_CXP9031366-R19E05
+ VM_image_SC-2: MTASv_4_CXP9031366-R19E05
+ PL_scheduling_policy: anti-affinity
+ om_net_name: mtas-41-1-nw_om_sp1
+ om_net_mtu: 1500
+ om_subnet_IPv4_name: mtas-41-1-nw_om_sp1_subnet_IPv4
+ om_subnet_IPv4_address: 10.80.103.8/29
+ om_subnet_IPv4_gateway_address: 10.80.103.9
+ om_subnet_IPv6_name: mtas-41-1-nw_om_sp1_subnet_IPv6
+ om_subnet_IPv6_address: 2001:1b70:8294:3d61::/64
+ om_subnet_IPv6_gateway_address: fe80::10:80:103:9
+ vipfrontend1_net_name: mtas-41-1-nw_om_sp2
+ vipfrontend1_net_mtu: 1500
+ vipfrontend2_net_name: mtas-41-1-nw_sig_sp
+ vipfrontend2_net_mtu: 1500
+ vipfrontend3_net_name: mtas-41-1-nw_bar_sp
+ vipfrontend3_net_mtu: 1500
+
+ mtas-55-10:
+ vim: *mtas-55-atlas
+ vnf-lcm: *mtas-55-vnflcm
+ project: MTAS-55-10
+ openrc: openrc-55-10
+ template-params:
+ legacy:
+ -p: "profile1"
+ -s: "ephemeral"
+ -v: "dualstack"
+ -n: "VLAN"
+ -b: "True"
+ jinja:
+ internal_network: one_int_net
+ vip_fe_network_number: 3
+ ip_version: ipv4ipv6
+ local_disk_realization: nova-ephemeral
+ ha_policy: none
+ network_type: VLAN
+ maximum_number_of_PLs: 10
+ port_security_vip_external: disable
+ port_security_non_vip_external: disable
+ env:
+ shared:
+ availability_zone: {'*':mtas}
+ VM_HA_policy_SC: managed-on-host
+ VM_HA_policy_PL: ha-offline
+ VM_image_PL: CXP9028685_1-R3A
+ SC-1_SC-2_cinder_volume_size: 50
+ number_of_scaled_out_VMs: 0
+ VM_to_be_scaled_in: []
+ nw_internal_mtu: 1500
+ OM_IPv4_address: 10.80.99.84
+ SC-1_IPv4_address: 10.80.99.85
+ SC-2_IPv4_address: 10.80.99.86
+ OM_IPv6_address: 2001:1b70:8294:3e1a::4
+ SC-1_IPv6_address: 2001:1b70:8294:3e1a::5
+ SC-2_IPv6_address: 2001:1b70:8294:3e1a::6
+ DNS_server_1_address: 10.51.40.100
+ DNS_server_2_address: 10.51.40.101
+ DNS_server_3_address: 10.64.73.100
+ DNS_server_4_address: 10.64.73.101
+ NTP_server_1_address: 10.51.40.102
+ NTP_server_2_address: 10.51.40.103
+ NTP_server_3_address: 10.64.73.102
+ NTP_server_4_address: 10.64.73.103
+ defaultURI: none
+ defaultSecURI: none
+ time_zone: Europe/Stockholm
+ watchdog_timeout: 30
+ interval_timeout: 10
+ shutdown_timeout: 600
+ platform-vip: 10.80.99.232
+ platform-vip6: 2001:1b70:8294:3e00::55a0
+ tasvip4: 10.80.99.233
+ tasvip6: 2001:1b70:8294:3e00::55a1
+ ut-vip4: 10.80.99.234
+ ut-vip6: 2001:1b70:8294:3e00::55a2
+ cai3g-vip4: 10.80.99.235
+ cai3g-vip6: 2001:1b70:8294:3e00::55a3
+ sigtran1-vip4: 10.80.99.236
+ sigtran1-vip6: 2001:1b70:8294:3e00::55a4
+ sigtran2-vip4: 10.80.99.237
+ sigtran2-vip6: 2001:1b70:8294:3e00::55a5
+ emergency_password_hash:
+ secla_password_hash:
+ root_password_hash:
+ oss_pm_password_hash:
+ DbnVMSharedMemoryPercentage: 37
+ DbnVMRecordHeapPercentage: 80
+ MultiMMapMaxMem: 32
+ jvm_initial_heap_size_Xms: 768m
+ jvm_initial_heap_size_eden_Xmn: 512m
+ jvm_max_heap_size_Xmx: 1536m
+ internal_net_mtu: 1500
+ mtu_cache_refresh_timer: 600
+ legacy:
+ VM_flavor_SC: vMTAS_4-27-200
+ VM_flavor_PL: vMTAS_4-27
+ VM_image_SC: MTASv_4_CXP9031366-R20C08
+ VM_image_SC_1: MTASv_4_CXP9031366-R20C08
+ VM_image_SC_2: MTASv_4_CXP9031366-R20C08
+ om_sp1_net_name: mtas-55-10-nw_om_sp1
+ om_sp1_net_mtu: 1500
+ om_sp1_subnet_IPv4_name: mtas-55-10-nw_om_sp1_subnet_IPv4
+ om_sp1_subnet_IPv4_address: 10.80.99.80/29
+ om_sp1_subnet_IPv4_gateway_address: 10.80.99.81
+ om_sp1_subnet_IPv6_name: mtas-55-10-nw_om_sp1_subnet_IPv6
+ om_sp1_subnet_IPv6_address: 2001:1b70:8294:3e1a::/64
+ om_sp1_subnet_IPv6_gateway_address: fe80::10:80:99:81
+ om_sp2_net_name: mtas-55-10-nw_om_sp2
+ om_sp2_net_mtu: 1500
+ sig_sp_net_name: mtas-55-10-nw_sig_sp
+ sig_sp_net_mtu: 1500
+ bar_sp_net_name: mtas-55-10-nw_bar_sp
+ bar_sp_net_mtu: 1500
+ jinja:
+ # VM_flavor_SC: vMTAS_16-54
+ # VM_flavor_PL: vMTAS_16-54
+ VM_flavor_SC: vMTAS_4-27-200
+ VM_flavor_PL: vMTAS_4-27
+ VM_image_SC: MTASv_4_CXP9031366-R20C08
+ VM_image_SC-1: MTASv_4_CXP9031366-R20C08
+ VM_image_SC-2: MTASv_4_CXP9031366-R20C08
+ PL_scheduling_policy: anti-affinity
+ om_net_name: mtas-55-10-nw_om_sp1
+ om_net_mtu: 1500
+ om_subnet_IPv4_name: mtas-55-10-nw_om_sp1_subnet_IPv4
+ om_subnet_IPv4_address: 10.80.99.80/29
+ om_subnet_IPv4_gateway_address: 10.80.99.81
+ om_subnet_IPv6_name: mtas-55-10-nw_om_sp1_subnet_IPv6
+ om_subnet_IPv6_address: 2001:1b70:8294:3e1a::/64
+ om_subnet_IPv6_gateway_address: fe80::10:80:99:81
+ vipfrontend1_net_name: mtas-55-10-nw_om_sp2
+ vipfrontend1_net_mtu: 1500
+ vipfrontend2_net_name: mtas-55-10-nw_sig_sp
+ vipfrontend2_net_mtu: 1500
+ vipfrontend3_net_name: mtas-55-10-nw_bar_sp
+ vipfrontend3_net_mtu: 1500
diff --git a/automatique.task.yaml.example b/automatique.task.yaml.example
new file mode 100644
index 0000000..c15910b
--- /dev/null
+++ b/automatique.task.yaml.example
@@ -0,0 +1,34 @@
+config:
+ git-branch: "" #origin/release/1.16
+ remote-host: mtas
+ lcmscript-path: "/n/tas/LCM_scripts_CT"
+ image-store: "/local/scratch/Images"
+ node: mtas-41-1
+ r-state: R19E05
+ arm-user:
+ arm-token:
+
+tasks:
+ - name: Build workflow release package
+ command: "standalone:workflow:build-package"
+ stored-args: [remote-host, lcmscript-path, git-branch]
+ provides: [workflow-package]
+ - name: Ensure image exists
+ command: "standalone:image:ensure-present"
+ stored-args: [remote-host, image-store, r-state]
+ - name: Upload image to glance
+ command: "standalone:atlas:upload-images"
+ stored-args: [remote-host, image-store, r-state, node]
+ - name: Prepare templates
+ command: "standalone:image:prepare-template"
+ stored-args: [remote-host, image-store, r-state, node]
+ - name: Generate onboard package
+ command: "standalone:workflow:generate-onboard-package"
+ stored-args: [remote-host, image-store, r-state, node, workflow-package]
+ provides: [onboard-package]
+ - name: Onboard package
+ command: "standalone:workflow:onboard-package"
+ stored-args: [remote-host, node, onboard-package]
+ - name: Cleanup
+ command: "standalone:cleanup-workplace"
+ stored-args: [remote-host, image-store, r-state, tmp-dir]
diff --git a/composer.json b/composer.json
index 5ffc459..10f8ab9 100644
--- a/composer.json
+++ b/composer.json
@@ -29,8 +29,10 @@
"symfony/console": "~4.0",
"symfony/process": "~4.0",
"symfony/yaml": "~4.0",
+ "twig/twig": "^3.0",
"zendframework/zend-component-installer": "^2.1.1",
"zendframework/zend-config-aggregator": "^1.0",
+ "zendframework/zend-http": "2.10.0",
"zendframework/zend-json": "3.1.0",
"zendframework/zend-servicemanager": "^3.3",
"zendframework/zend-stdlib": "^3.1"
diff --git a/composer.lock b/composer.lock
index 469d1c1..3e18ec7 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "f71f8d197648c0e6aaf75d3877a47421",
+ "content-hash": "a21e30c1186a64be189bd5eb128f2561",
"packages": [
{
"name": "container-interop/container-interop",
@@ -35,6 +35,7 @@
],
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"homepage": "https://github.com/container-interop/container-interop",
+ "abandoned": "psr/container",
"time": "2017-02-14T19:40:03+00:00"
},
{
@@ -664,6 +665,70 @@
"homepage": "https://symfony.com",
"time": "2019-09-11T15:41:19+00:00"
},
+ {
+ "name": "twig/twig",
+ "version": "v3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/twigphp/Twig.git",
+ "reference": "9b58bb8ac7a41d72fbb5a7dc643e07923e5ccc26"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/9b58bb8ac7a41d72fbb5a7dc643e07923e5ccc26",
+ "reference": "9b58bb8ac7a41d72fbb5a7dc643e07923e5ccc26",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.9",
+ "symfony/polyfill-ctype": "^1.8",
+ "symfony/polyfill-mbstring": "^1.3"
+ },
+ "require-dev": {
+ "psr/container": "^1.0",
+ "symfony/debug": "^3.4|^4.2|^5.0",
+ "symfony/phpunit-bridge": "^4.4@dev|^5.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Twig\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com",
+ "homepage": "http://fabien.potencier.org",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Twig Team",
+ "homepage": "https://twig.symfony.com/contributors",
+ "role": "Contributors"
+ },
+ {
+ "name": "Armin Ronacher",
+ "email": "armin.ronacher@active-4.com",
+ "role": "Project Founder"
+ }
+ ],
+ "description": "Twig, the flexible, fast, and secure template language for PHP",
+ "homepage": "https://twig.symfony.com",
+ "keywords": [
+ "templating"
+ ],
+ "time": "2019-11-15T20:38:32+00:00"
+ },
{
"name": "zendframework/zend-component-installer",
"version": "2.1.2",
@@ -771,6 +836,106 @@
],
"time": "2018-04-04T20:37:31+00:00"
},
+ {
+ "name": "zendframework/zend-escaper",
+ "version": "2.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zendframework/zend-escaper.git",
+ "reference": "3801caa21b0ca6aca57fa1c42b08d35c395ebd5f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zendframework/zend-escaper/zipball/3801caa21b0ca6aca57fa1c42b08d35c395ebd5f",
+ "reference": "3801caa21b0ca6aca57fa1c42b08d35c395ebd5f",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2",
+ "zendframework/zend-coding-standard": "~1.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.6.x-dev",
+ "dev-develop": "2.7.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Zend\\Escaper\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs",
+ "keywords": [
+ "ZendFramework",
+ "escaper",
+ "zf"
+ ],
+ "time": "2019-09-05T20:03:20+00:00"
+ },
+ {
+ "name": "zendframework/zend-http",
+ "version": "2.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zendframework/zend-http.git",
+ "reference": "4b4983178693a8fdda53b0bbee58552e2d2b1ac0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zendframework/zend-http/zipball/4b4983178693a8fdda53b0bbee58552e2d2b1ac0",
+ "reference": "4b4983178693a8fdda53b0bbee58552e2d2b1ac0",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0",
+ "zendframework/zend-loader": "^2.5.1",
+ "zendframework/zend-stdlib": "^3.2.1",
+ "zendframework/zend-uri": "^2.5.2",
+ "zendframework/zend-validator": "^2.10.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.3",
+ "zendframework/zend-coding-standard": "~1.0.0",
+ "zendframework/zend-config": "^3.1 || ^2.6"
+ },
+ "suggest": {
+ "paragonie/certainty": "For automated management of cacert.pem"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.10.x-dev",
+ "dev-develop": "2.11.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Zend\\Http\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Provides an easy interface for performing Hyper-Text Transfer Protocol (HTTP) requests",
+ "keywords": [
+ "ZendFramework",
+ "http",
+ "http client",
+ "zend",
+ "zf"
+ ],
+ "time": "2019-02-19T18:58:14+00:00"
+ },
{
"name": "zendframework/zend-json",
"version": "3.1.0",
@@ -821,6 +986,51 @@
],
"time": "2018-01-04T17:51:34+00:00"
},
+ {
+ "name": "zendframework/zend-loader",
+ "version": "2.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zendframework/zend-loader.git",
+ "reference": "91da574d29b58547385b2298c020b257310898c6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zendframework/zend-loader/zipball/91da574d29b58547385b2298c020b257310898c6",
+ "reference": "91da574d29b58547385b2298c020b257310898c6",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4",
+ "zendframework/zend-coding-standard": "~1.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.6.x-dev",
+ "dev-develop": "2.7.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Zend\\Loader\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Autoloading and plugin loading strategies",
+ "keywords": [
+ "ZendFramework",
+ "loader",
+ "zf"
+ ],
+ "time": "2019-09-04T19:38:14+00:00"
+ },
{
"name": "zendframework/zend-servicemanager",
"version": "3.4.0",
@@ -934,6 +1144,126 @@
"zf"
],
"time": "2018-08-28T21:34:05+00:00"
+ },
+ {
+ "name": "zendframework/zend-uri",
+ "version": "2.7.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zendframework/zend-uri.git",
+ "reference": "bfc4a5b9a309711e968d7c72afae4ac50c650083"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zendframework/zend-uri/zipball/bfc4a5b9a309711e968d7c72afae4ac50c650083",
+ "reference": "bfc4a5b9a309711e968d7c72afae4ac50c650083",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0",
+ "zendframework/zend-escaper": "^2.5",
+ "zendframework/zend-validator": "^2.10"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4",
+ "zendframework/zend-coding-standard": "~1.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7.x-dev",
+ "dev-develop": "2.8.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Zend\\Uri\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "A component that aids in manipulating and validating » Uniform Resource Identifiers (URIs)",
+ "keywords": [
+ "ZendFramework",
+ "uri",
+ "zf"
+ ],
+ "time": "2019-10-07T13:35:33+00:00"
+ },
+ {
+ "name": "zendframework/zend-validator",
+ "version": "2.12.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zendframework/zend-validator.git",
+ "reference": "fd24920c2afcf2a70d11f67c3457f8f509453a62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zendframework/zend-validator/zipball/fd24920c2afcf2a70d11f67c3457f8f509453a62",
+ "reference": "fd24920c2afcf2a70d11f67c3457f8f509453a62",
+ "shasum": ""
+ },
+ "require": {
+ "container-interop/container-interop": "^1.1",
+ "php": "^5.6 || ^7.0",
+ "zendframework/zend-stdlib": "^3.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0.8 || ^5.7.15",
+ "psr/http-message": "^1.0",
+ "zendframework/zend-cache": "^2.6.1",
+ "zendframework/zend-coding-standard": "~1.0.0",
+ "zendframework/zend-config": "^2.6",
+ "zendframework/zend-db": "^2.7",
+ "zendframework/zend-filter": "^2.6",
+ "zendframework/zend-http": "^2.5.4",
+ "zendframework/zend-i18n": "^2.6",
+ "zendframework/zend-math": "^2.6",
+ "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3",
+ "zendframework/zend-session": "^2.8",
+ "zendframework/zend-uri": "^2.5"
+ },
+ "suggest": {
+ "psr/http-message": "psr/http-message, required when validating PSR-7 UploadedFileInterface instances via the Upload and UploadFile validators",
+ "zendframework/zend-db": "Zend\\Db component, required by the (No)RecordExists validator",
+ "zendframework/zend-filter": "Zend\\Filter component, required by the Digits validator",
+ "zendframework/zend-i18n": "Zend\\I18n component to allow translation of validation error messages",
+ "zendframework/zend-i18n-resources": "Translations of validator messages",
+ "zendframework/zend-math": "Zend\\Math component, required by the Csrf validator",
+ "zendframework/zend-servicemanager": "Zend\\ServiceManager component to allow using the ValidatorPluginManager and validator chains",
+ "zendframework/zend-session": "Zend\\Session component, ^2.8; required by the Csrf validator",
+ "zendframework/zend-uri": "Zend\\Uri component, required by the Uri and Sitemap\\Loc validators"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.12.x-dev",
+ "dev-develop": "2.13.x-dev"
+ },
+ "zf": {
+ "component": "Zend\\Validator",
+ "config-provider": "Zend\\Validator\\ConfigProvider"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Zend\\Validator\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Validation classes for a wide range of domains, and the ability to chain validators to create complex validation criteria",
+ "keywords": [
+ "ZendFramework",
+ "validator",
+ "zf"
+ ],
+ "time": "2019-10-29T08:33:25+00:00"
}
],
"packages-dev": [
diff --git a/config/config.php b/config/config.php
index fcf64ac..17f8d8c 100644
--- a/config/config.php
+++ b/config/config.php
@@ -13,6 +13,7 @@ $cacheConfig = [
];
$aggregator = new ConfigAggregator([
+ \Zend\Validator\ConfigProvider::class,
// Include cache configuration
new ArrayProvider($cacheConfig),
diff --git a/src/App/Command/AutoOptions.php b/src/App/Command/AutoOptions.php
new file mode 100644
index 0000000..31982a8
--- /dev/null
+++ b/src/App/Command/AutoOptions.php
@@ -0,0 +1,37 @@
+addOption($option, null, InputOption::VALUE_REQUIRED, "", null);
+ }
+ }
+
+ /**
+ * @param InputInterface $input
+ * @return array
+ * @throws Exception
+ */
+ protected function getFunctionArgs(InputInterface $input): array
+ {
+ $functionArgs = [];
+ foreach (self::OPTIONS as $key => $option) {
+ if (null === ($value = $input->getOption($option))) {
+ throw new Exception("Missing option: $option");
+ }
+ $this->saveToShared($option, $value);
+ $functionArgs[] = $value;
+ }
+ return $functionArgs;
+ }
+}
diff --git a/src/App/Command/BuildPackage.php b/src/App/Command/BuildPackage.php
index a526013..3213c0d 100644
--- a/src/App/Command/BuildPackage.php
+++ b/src/App/Command/BuildPackage.php
@@ -4,22 +4,24 @@ declare(strict_types=1);
namespace App\Command;
-use App\Downloader\SCP;
use App\Service\Builder;
use Doctrine\Common\Collections\Collection;
use Exception;
use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Helper\ProgressBar;
-use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Process\Process;
class BuildPackage extends Command
{
- use SharedStorage;
- const NAME = "standalone:build-package";
+ use SharedStorage,
+ AutoOptions;
+
+ const NAME = "standalone:workflow:build-package";
+ const OPTIONS = [
+ "remote-host",
+ "lcmscript-path",
+ "git-branch",
+ ];
/** @var Builder */
private $builder;
@@ -33,17 +35,8 @@ class BuildPackage extends Command
protected function configure()
{
- $this
- ->setName(self::NAME)
- ->setDescription('Build packages on remote host')
- ->addOption("host", null, InputOption::VALUE_REQUIRED, "", false)
- ->addOption("path", null, InputOption::VALUE_REQUIRED, "", false)
- ;
- }
-
- protected function saveToShared(string $name, $value)
- {
- $this->sharedStorage->set(sprintf("%s:%s", self::NAME, $name), $value);
+ $this->setName(self::NAME)->setDescription('Build packages on remote host');
+ $this->configureOptions();
}
/**
@@ -53,30 +46,8 @@ class BuildPackage extends Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
- $host = $input->getOption("host");
- $path = $input->getOption("path");
- if (!$host && !$path) {
- throw new Exception("Missing arguments");
- }
- $this->saveToShared("host", $host);
- $this->saveToShared("path", $path);
- $output->writeln("Building package:");
-// $helper = $this->getHelper('process');
-// $tableSection = $output->section();
-// $totalProgressSection = $output->section();
-// $itemProgressSection = $output->section();
-// $table = new Table($tableSection);
-// $table->setHeaders([
-// 'Title',
-// 'Pages',
-// 'Size',
-// ]);
-// $table->render();
-// $totalProgress = new ProgressBar($totalProgressSection);
-// $itemProgress = new ProgressBar($itemProgressSection);
- $remotePackage = $this->builder->buildRemotePackage($host, $path);
- $this->saveToShared("package", $remotePackage);
- $downloader = new SCP();
- $downloader->download(sprintf("%s:%s", $host, $remotePackage), ".");
+ $funcArgs = $this->getFunctionArgs($input);
+ $remotePackage = $this->builder->buildRemotePackage(...$funcArgs);
+ $this->saveToShared("workflow-package", $remotePackage);
}
}
diff --git a/src/App/Command/Cleanup.php b/src/App/Command/Cleanup.php
new file mode 100644
index 0000000..57f3e32
--- /dev/null
+++ b/src/App/Command/Cleanup.php
@@ -0,0 +1,52 @@
+cleanup = $cleanup;
+ $this->sharedStorage = $storage;
+ parent::__construct();
+ }
+
+ protected function configure()
+ {
+ $this->setName(self::NAME)->setDescription('Cleanup workspace');
+ $this->configureOptions();;
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @throws Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $functionArgs = $this->getFunctionArgs($input);
+ $this->cleanup->cleanup(...$functionArgs);
+ }
+}
diff --git a/src/App/Command/CleanupFactory.php b/src/App/Command/CleanupFactory.php
new file mode 100644
index 0000000..46955fb
--- /dev/null
+++ b/src/App/Command/CleanupFactory.php
@@ -0,0 +1,21 @@
+get(ArrayCollection::class);
+ /** @var \App\Service\Cleanup $cleaner */
+ $cleaner = $container->get(\App\Service\Cleanup::class);
+ return new Cleanup($cleaner, $sharedStorage);
+ }
+}
diff --git a/src/App/Command/ComplexTaskConfig.php b/src/App/Command/ComplexTaskConfig.php
index 3b16832..fcce480 100644
--- a/src/App/Command/ComplexTaskConfig.php
+++ b/src/App/Command/ComplexTaskConfig.php
@@ -8,18 +8,28 @@ use App\Service\ConfigProvider;
use Doctrine\Common\Collections\ArrayCollection;
use Exception;
use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class ComplexTaskConfig extends Command
{
+ use SharedStorage;
+
+ const INPUT_OPTIONS = [
+ 'remote-host' => 'Remote host used to build the packages',
+ 'lcmscript-path' => 'Where to find the lcmScripts to package',
+ 'image-store' => 'Where to store the downloaded images',
+ 'node' => 'Node to use in the generated package',
+ 'r-state' => 'R-state of vMTAS image',
+ 'git-branch' => 'Git branch to check out',
+ ];
+
/** @var ConfigProvider */
private $configProvider;
- /** @var ArrayCollection */
- private $sharedStorage;
-
public function __construct(ConfigProvider $configProvider, ArrayCollection $sharedStorage)
{
$this->configProvider = $configProvider;
@@ -31,6 +41,36 @@ class ComplexTaskConfig extends Command
{
$this->setName('complex:task-config')
->setDescription('Build using task config');
+ foreach (self::INPUT_OPTIONS as $option => $description) {
+ $this->addOption($option, null, InputOption::VALUE_REQUIRED, $description, false);
+ }
+ }
+
+ private function getProgressBar(OutputInterface $output): ProgressBar
+ {
+ $totalProgress = new ProgressBar($output);
+ $totalProgress->setMessage($this->getDescription());
+ $totalProgress->setFormat(" %message:-45s%>\n%current%/%max% [%bar%] %percent:3s%%\n%elapsed:-20s% %memory:20s%");
+ $totalProgress->setBarCharacter("●>");
+ $totalProgress->setEmptyBarCharacter("●>");
+ $totalProgress->setProgressCharacter("➤>");
+ return $totalProgress;
+ }
+
+ private function parseSharedTaskConfig(array $config): void
+ {
+ foreach ($config as $key => $item) {
+ $this->saveToShared($key, $item);
+ }
+ }
+
+ private function parseInputOptions(InputInterface $input): void
+ {
+ foreach (self::INPUT_OPTIONS as $option => $_) {
+ if (false !== ($value = $input->getOption($option))) {
+ $this->saveToShared($option, $value);
+ }
+ }
}
/**
@@ -41,23 +81,30 @@ class ComplexTaskConfig extends Command
protected function execute(InputInterface $input, OutputInterface $output)
{
$taskConfig = $this->configProvider->getTaskConfig();
+ $this->parseSharedTaskConfig($taskConfig['config']);
+ $this->parseInputOptions($input);
$app = $this->getApplication();
- foreach ($taskConfig as $task) {
+ $totalProgress = $this->getProgressBar($output);
+ foreach ($totalProgress->iterate($taskConfig['tasks']) as $task) {
+ $totalProgress->setMessage($task['name']);
$cmd = $app->find($task['command']);
$args = [
'command' => $task['command']
];
if (isset($task['args']) && is_array($task['args'])) {
- $args += $task['args'];
+ foreach ($task['args'] as $key => $arg) {
+ $args["--${key}"] = $arg;
+ }
}
if (isset($task['stored-args']) && is_array($task['stored-args'])) {
- foreach ($task['stored-args'] as $key => $storedArg) {
- $args[$key] = $this->sharedStorage->get($storedArg);
+ foreach ($task['stored-args'] as $storedArg) {
+ $args["--${storedArg}"] = $this->sharedStorage->get("args:${storedArg}");
}
}
$cmd->run(new ArrayInput($args), $output);
}
+ $output->writeln("");
}
}
diff --git a/src/App/Command/DownloadArmImage.php b/src/App/Command/DownloadArmImage.php
new file mode 100644
index 0000000..538a4f4
--- /dev/null
+++ b/src/App/Command/DownloadArmImage.php
@@ -0,0 +1,44 @@
+downloader = $downloader;
+ parent::__construct();
+ }
+
+ protected function configure()
+ {
+ $this->setName(self::NAME)
+ ->setDescription('Generate onboard package')
+ ->addArgument("r-state", InputArgument::REQUIRED);
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @throws Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $rState = $input->getArgument("r-state");
+ $this->downloader->downloadImage($rState);
+ }
+}
diff --git a/src/App/Command/DownloadArmImageFactory.php b/src/App/Command/DownloadArmImageFactory.php
new file mode 100644
index 0000000..5cd95dc
--- /dev/null
+++ b/src/App/Command/DownloadArmImageFactory.php
@@ -0,0 +1,18 @@
+get(ArmImageDownloader::class);
+ return new DownloadArmImage($downloader);
+ }
+}
diff --git a/src/App/Command/EnsureImagePresent.php b/src/App/Command/EnsureImagePresent.php
new file mode 100644
index 0000000..10c4a69
--- /dev/null
+++ b/src/App/Command/EnsureImagePresent.php
@@ -0,0 +1,55 @@
+downloader = $downloader;
+ $this->sharedStorage = $storage;
+ parent::__construct();
+ }
+
+ protected function configure()
+ {
+ $this->setName(self::NAME)->setDescription('Generate onboard package');
+ $this->configureOptions();;
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @throws Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $functionArgs = $this->getFunctionArgs($input);
+ if ($this->downloader->isRemoteImageMissing(...$functionArgs)) {
+ $this->downloader->downloadImageToRemote(...$functionArgs);
+ }
+ $this->downloader->uncompressImage(...$functionArgs);
+ }
+}
diff --git a/src/App/Command/EnsureImagePresentFactory.php b/src/App/Command/EnsureImagePresentFactory.php
new file mode 100644
index 0000000..0f55829
--- /dev/null
+++ b/src/App/Command/EnsureImagePresentFactory.php
@@ -0,0 +1,21 @@
+get(ArmImageDownloader::class);
+ /** @var ArrayCollection $sharedStorage */
+ $sharedStorage = $container->get(ArrayCollection::class);
+ return new EnsureImagePresent($downloader, $sharedStorage);
+ }
+}
diff --git a/src/App/Command/GenerateOnboardPackage.php b/src/App/Command/GenerateOnboardPackage.php
index ba61860..4608c2d 100644
--- a/src/App/Command/GenerateOnboardPackage.php
+++ b/src/App/Command/GenerateOnboardPackage.php
@@ -9,13 +9,23 @@ use Doctrine\Common\Collections\Collection;
use Exception;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class GenerateOnboardPackage extends Command
{
- use SharedStorage;
- const NAME = "standalone:generate-onboard-package";
+ use SharedStorage,
+ AutoOptions;
+
+ const NAME = "standalone:workflow:generate-onboard-package";
+ const OPTIONS = [
+ "remote-host",
+ "image-store",
+ "r-state",
+ "node",
+ "workflow-package",
+ ];
+
+ const PACKAGE_MATCH = "/.*Package ZIP file \[(.*?)\] has been created.*/msi";
/** @var Builder */
private $builder;
@@ -29,12 +39,8 @@ class GenerateOnboardPackage extends Command
protected function configure()
{
- $this
- ->setName(self::NAME)
- ->setDescription('Gen onboard package')
- ->addOption("host", null, InputOption::VALUE_REQUIRED, "", false)
- ->addOption("package", null, InputOption::VALUE_REQUIRED, "", false)
- ;
+ $this->setName(self::NAME)->setDescription('Generate onboard package');
+ $this->configureOptions();;
}
/**
@@ -44,14 +50,9 @@ class GenerateOnboardPackage extends Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
- $host = $input->getOption("host");
- $package = $input->getOption("package");
- if (!$host && !$package) {
- throw new Exception("Missing arguments");
- }
- $this->saveToShared("host", $host);
- $this->saveToShared("path", $package);
- $output->writeln("Generate onboard package:");
- $output->writeln("Got args: " . $input->getOption("host") . $input->getOption("package"));
+ $functionArgs = $this->getFunctionArgs($input);
+ $sshResult = $this->builder->createOnboardPackage(...$functionArgs);
+ preg_match(self::PACKAGE_MATCH, $sshResult, $matches);
+ $this->saveToShared("onboard-package", $matches[1]);
}
}
diff --git a/src/App/Command/ListNodeImages.php b/src/App/Command/ListNodeImages.php
new file mode 100644
index 0000000..cd9a41c
--- /dev/null
+++ b/src/App/Command/ListNodeImages.php
@@ -0,0 +1,51 @@
+atlasManager = $atlasManager;
+ parent::__construct();
+ }
+
+ protected function configure()
+ {
+ $this->setName(self::NAME)->setDescription('Build packages on remote host');
+ $this->configureOptions();
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @throws Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+// $funcArgs = $this->getFunctionArgs($input);
+ $images = $this->atlasManager->listImages();
+ $table = new Table($output);
+ $table->addRows($images);
+ $table->render();
+ }
+}
diff --git a/src/App/Command/ListNodeImagesFactory.php b/src/App/Command/ListNodeImagesFactory.php
new file mode 100644
index 0000000..04cf1be
--- /dev/null
+++ b/src/App/Command/ListNodeImagesFactory.php
@@ -0,0 +1,18 @@
+get(AtlasManager::class);
+ return new ListNodeImages($atlasManager);
+ }
+}
diff --git a/src/App/Command/OnboardPackage.php b/src/App/Command/OnboardPackage.php
new file mode 100644
index 0000000..8507c50
--- /dev/null
+++ b/src/App/Command/OnboardPackage.php
@@ -0,0 +1,52 @@
+builder = $builder;
+ $this->sharedStorage = $storage;
+ parent::__construct();
+ }
+
+ protected function configure()
+ {
+ $this->setName(self::NAME)->setDescription('Generate onboard package');
+ $this->configureOptions();;
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @throws Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $functionArgs = $this->getFunctionArgs($input);
+ $this->builder->onboardPackage(...$functionArgs);
+ }
+}
diff --git a/src/App/Command/OnboardPackageFactory.php b/src/App/Command/OnboardPackageFactory.php
new file mode 100644
index 0000000..0098e0f
--- /dev/null
+++ b/src/App/Command/OnboardPackageFactory.php
@@ -0,0 +1,20 @@
+get(Builder::class);
+ $sharedStorage = $container->get(ArrayCollection::class);
+ return new OnboardPackage($builder, $sharedStorage);
+ }
+}
diff --git a/src/App/Command/PrepareTemplates.php b/src/App/Command/PrepareTemplates.php
new file mode 100644
index 0000000..2aef00b
--- /dev/null
+++ b/src/App/Command/PrepareTemplates.php
@@ -0,0 +1,53 @@
+templateGenerator = $templateGenerator;
+ $this->sharedStorage = $storage;
+ parent::__construct();
+ }
+
+ protected function configure()
+ {
+ $this->setName(self::NAME)->setDescription('Generate templates');
+ $this->configureOptions();
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @throws Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $funcArgs = $this->getFunctionArgs($input);
+ $this->templateGenerator->generateTemplates(...$funcArgs);
+ }
+}
diff --git a/src/App/Command/PrepareTemplatesFactory.php b/src/App/Command/PrepareTemplatesFactory.php
new file mode 100644
index 0000000..0833d78
--- /dev/null
+++ b/src/App/Command/PrepareTemplatesFactory.php
@@ -0,0 +1,21 @@
+get(TemplateGenerator::class);
+ /** @var ArrayCollection $sharedStorage */
+ $sharedStorage = $container->get(ArrayCollection::class);
+ return new PrepareTemplates($templateGenerator, $sharedStorage);
+ }
+}
diff --git a/src/App/Command/SharedStorage.php b/src/App/Command/SharedStorage.php
index 5a4bda5..b834315 100644
--- a/src/App/Command/SharedStorage.php
+++ b/src/App/Command/SharedStorage.php
@@ -13,6 +13,6 @@ trait SharedStorage
protected function saveToShared(string $name, $value)
{
- $this->sharedStorage->set(sprintf("%s:%s", self::NAME, $name), $value);
+ $this->sharedStorage->set(sprintf("args:%s", $name), $value);
}
}
diff --git a/src/App/Command/UploadImage.php b/src/App/Command/UploadImage.php
new file mode 100644
index 0000000..a72dfbe
--- /dev/null
+++ b/src/App/Command/UploadImage.php
@@ -0,0 +1,53 @@
+atlasManager = $atlasManager;
+ $this->sharedStorage = $storage;
+ parent::__construct();
+ }
+
+ protected function configure()
+ {
+ $this->setName(self::NAME)->setDescription('Build packages on remote host');
+ $this->configureOptions();
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @throws Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $funcArgs = $this->getFunctionArgs($input);
+ $this->atlasManager->ensureImageIsInGlance(...$funcArgs);
+ }
+}
diff --git a/src/App/Command/UploadImageFactory.php b/src/App/Command/UploadImageFactory.php
new file mode 100644
index 0000000..b394d46
--- /dev/null
+++ b/src/App/Command/UploadImageFactory.php
@@ -0,0 +1,21 @@
+get(AtlasManager::class);
+ /** @var ArrayCollection $sharedStorage */
+ $sharedStorage = $container->get(ArrayCollection::class);
+ return new UploadImage($atlasManager, $sharedStorage);
+ }
+}
diff --git a/src/App/ConfigProvider.php b/src/App/ConfigProvider.php
index dfb6744..9a795c5 100644
--- a/src/App/ConfigProvider.php
+++ b/src/App/ConfigProvider.php
@@ -41,10 +41,20 @@ class ConfigProvider
'factories' => [
Service\Builder::class => Service\BuilderFactory::class,
Service\ConfigProvider::class => Service\ConfigProviderFactory::class,
+ Service\ArmImageDownloader::class => Service\ArmImageDownloaderFactory::class,
+ Service\TemplateGenerator::class => Service\TemplateGeneratorFactory::class,
+ Service\Cleanup::class => Service\CleanupFactory::class,
+ Service\AtlasManager::class => Service\AtlasManagerFactory::class,
- Command\BuildPackage::class => Command\BuildPackageFactory::class,
Command\ComplexTaskConfig::class => Command\ComplexTaskConfigFactory::class,
+ Command\BuildPackage::class => Command\BuildPackageFactory::class,
Command\GenerateOnboardPackage::class => Command\GenerateOnboardPackageFactory::class,
+ Command\OnboardPackage::class => Command\OnboardPackageFactory::class,
+ Command\DownloadArmImage::class => Command\DownloadArmImageFactory::class,
+ Command\EnsureImagePresent::class => Command\EnsureImagePresentFactory::class,
+ Command\PrepareTemplates::class => Command\PrepareTemplatesFactory::class,
+ Command\Cleanup::class => Command\CleanupFactory::class,
+ Command\UploadImage::class => Command\UploadImageFactory::class,
],
];
}
@@ -61,6 +71,12 @@ class ConfigProvider
'lazy_commands' => [
Command\BuildPackage::NAME => Command\BuildPackage::class,
Command\GenerateOnboardPackage::NAME => Command\GenerateOnboardPackage::class,
+ Command\OnboardPackage::NAME => Command\OnboardPackage::class,
+ Command\DownloadArmImage::NAME => Command\DownloadArmImage::class,
+ Command\EnsureImagePresent::NAME => Command\EnsureImagePresent::class,
+ Command\PrepareTemplates::NAME => Command\PrepareTemplates::class,
+ Command\Cleanup::NAME => Command\Cleanup::class,
+ Command\UploadImage::NAME => Command\UploadImage::class,
],
];
}
diff --git a/src/App/Downloader/SCP.php b/src/App/Downloader/SCP.php
index beab1b5..26a7936 100644
--- a/src/App/Downloader/SCP.php
+++ b/src/App/Downloader/SCP.php
@@ -11,7 +11,7 @@ class SCP implements DownloaderInterface
public function download(string $remote, string $local): string
{
$process = new Process([
- 'scp',
+ 'scp', '-q',
$remote,
$local
]);
diff --git a/src/App/Runner/RunnerInterface.php b/src/App/Runner/RunnerInterface.php
index 13a9695..ff480f1 100644
--- a/src/App/Runner/RunnerInterface.php
+++ b/src/App/Runner/RunnerInterface.php
@@ -5,5 +5,5 @@ declare(strict_types=1);
namespace App\Runner;
interface RunnerInterface {
- public function execute($command): string;
+ public function execute(string $command): string;
}
\ No newline at end of file
diff --git a/src/App/Runner/SSH.php b/src/App/Runner/SSH.php
index 00bc389..eec509b 100644
--- a/src/App/Runner/SSH.php
+++ b/src/App/Runner/SSH.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Runner;
+use Exception;
use Symfony\Component\Process\Process;
class SSH implements RunnerInterface
@@ -15,17 +16,60 @@ class SSH implements RunnerInterface
$this->hostname = $hostname;
}
- public function execute($command): string
+ /**
+ * @param string $command
+ * @return string
+ * @throws Exception
+ */
+ public function execute(string $command): string
{
$process = new Process([
- 'ssh',
+ 'ssh', '-q',
$this->hostname,
$command
]);
+ $process->setTimeout(180);
$process->run();
if (!$process->isSuccessful()) {
- throw new \Exception("Command failed with: " . $process->getErrorOutput());
+ throw new Exception("Command failed with: " . $process->getErrorOutput());
}
return $process->getOutput();
}
+
+ /**
+ * @param $src
+ * @param $dst
+ */
+ public function copyToRemote($src, $dst)
+ {
+ $process = new Process([
+ 'scp', '-q',
+ $src,
+ sprintf("%s:${dst}", $this->hostname)
+ ]);
+ $process->setTimeout(180);
+ $process->run();
+ }
+
+ /**
+ * @param $file
+ * @return string
+ * @throws Exception
+ */
+ public function readFile($file): string
+ {
+ return $this->execute("cat ${file}");
+ }
+
+ /**
+ * @param $file
+ * @param $content
+ */
+ public function saveFile($file, $content)
+ {
+ $tmpFile = tempnam(sys_get_temp_dir(), 'atmq');
+ file_put_contents($tmpFile, $content);
+ $this->copyToRemote($tmpFile, $file);
+ unlink($tmpFile);
+ }
}
diff --git a/src/App/Service/ArmImageDownloader.php b/src/App/Service/ArmImageDownloader.php
new file mode 100644
index 0000000..f4e5054
--- /dev/null
+++ b/src/App/Service/ArmImageDownloader.php
@@ -0,0 +1,73 @@
+httpClient = $httpClient;
+ $this->configProvider = $appConfig;
+ }
+
+ public function downloadImage(string $rState): bool
+ {
+ $config = $this->configProvider->getTaskConfig()['config'];
+ $uri = self::ARM_URL . self::ARM_IMAGE_PATH . self::IMAGE_NAME;
+ $response = $this->httpClient->setStream(sprintf(self::IMAGE_NAME, $rState))
+ ->setUri(sprintf($uri, $rState))
+ ->setAuth($config['arm-user'], $config['arm-token'])
+ ->send()
+ ;
+ return $response->isSuccess();
+ }
+
+ public function downloadImageToRemote(string $host, string $path, string $rState): bool
+ {
+ $ssh = new SSH($host);
+ $ssh->execute("mkdir -p ${path}/${rState}");
+ $imageUrl = sprintf(self::ARM_URL . self::ARM_IMAGE_PATH . self::IMAGE_NAME, $rState);
+ $imageFile = sprintf(self::IMAGE_NAME, $rState);
+ $ssh->execute("curl ${imageUrl} --silent --output ${path}/${rState}/${imageFile}");
+ return true;
+ }
+
+ public function isRemoteImageMissing(string $host, string $path, string $rState): bool
+ {
+ $ssh = new SSH($host);
+ try {
+ $ssh->execute("ls -1 ${path}/${rState}/" . sprintf(self::IMAGE_NAME, $rState));
+ } catch (Exception $_) {
+ return true;
+ }
+ return false;
+ }
+
+ public function uncompressImage(string $host, string $path, string $rState): bool
+ {
+ $ssh = new SSH($host);
+ $imageFile = sprintf(self::IMAGE_NAME, $rState);
+ $imageDir = "${path}/${rState}";
+ $targetDir = "${imageDir}/uncompressed";
+ $ssh->execute("rm -rf ${targetDir}");
+ $ssh->execute("mkdir -p ${targetDir}");
+ $ssh->execute("tar xf ${imageDir}/$imageFile -C ${targetDir}");
+ return true;
+ }
+}
diff --git a/src/App/Service/ArmImageDownloaderFactory.php b/src/App/Service/ArmImageDownloaderFactory.php
new file mode 100644
index 0000000..5d63d32
--- /dev/null
+++ b/src/App/Service/ArmImageDownloaderFactory.php
@@ -0,0 +1,19 @@
+get(ConfigProvider::class);
+ return new ArmImageDownloader($client, $appConfig);
+ }
+}
diff --git a/src/App/Service/AtlasManager.php b/src/App/Service/AtlasManager.php
new file mode 100644
index 0000000..0fa92c1
--- /dev/null
+++ b/src/App/Service/AtlasManager.php
@@ -0,0 +1,120 @@
+envConfig = $envConfig;
+ }
+
+ private static function openstackCommand(string $cmd): string
+ {
+ return sprintf("source openrc && %s", $cmd);
+ }
+
+ /**
+ * @param SSH $ssh
+ * @return array|null
+ * @throws Exception
+ */
+ public function listImages(SSH $ssh): ?array
+ {
+ $glanceOutput = $ssh->execute(self::openstackCommand(self::GLANCE_LIST));
+ return Json::decode($glanceOutput, Json::TYPE_ARRAY);
+ }
+
+ /**
+ * @param SSH $ssh
+ * @param string $imageName
+ * @return bool
+ * @throws Exception
+ */
+ public function isImageInGlance(SSH $ssh, string $imageName): bool
+ {
+ $glanceImages = $this->listImages($ssh);
+ $filtered = array_filter($glanceImages, function($record) use ($imageName) {
+ return $record['Name'] == $imageName;
+ });
+ $count = count($filtered);
+ if ($count > 1) {
+ throw new Exception("Multiple images exist with the same name, can't decide on what to use");
+ }
+ return $count == 1;
+ }
+
+ /**
+ * @param SSH $ssh
+ * @param string $imageFile
+ * @param string $dst
+ * @throws Exception
+ */
+ public function copyImageToAtlas(SSH $ssh, string $imageFile, string $dst)
+ {
+ $ssh->execute("scp -q ${imageFile} ${dst}");
+ }
+
+ /**
+ * @param SSH $ssh
+ * @param string $imageName
+ * @return bool
+ */
+ public function uploadImageToGlance(SSH $ssh, string $imageName): bool
+ {
+ try {
+ $imageFile = sprintf("/tmp/%s.qcow2", $imageName);
+ $out = $ssh->execute(self::openstackCommand(sprintf(
+ self::GLANCE_UPLOAD,
+ $imageFile,
+ $imageName
+ )));
+ return true;
+ } catch (Exception $_) {
+ return false;
+ }
+ }
+
+ /**
+ * @param string $host
+ * @param string $imageDir
+ * @param string $rState
+ * @param string $node
+ * @throws Exception
+ */
+ public function ensureImageIsInGlance(string $host, string $imageDir, string $rState, string $node)
+ {
+ $vimCfg = $this->envConfig['node'][$node]['vim'];
+
+ $workerSSH = new SSH($host);
+ $atlasSSH = new SSH($vimCfg['ssh-alias']);
+
+ $imageName = sprintf(self::IMAGE_NAME_BASE, $rState);
+ if ($this->isImageInGlance($atlasSSH, $imageName)) {
+ return;
+ }
+ $imageSourceFile = sprintf("${imageDir}/${rState}/uncompressed/" . self::IMAGE_NAME_BASE . ".qcow2", $rState);
+ $atlasFileName = sprintf("/tmp/" . self::IMAGE_NAME_BASE . ".qcow2", $rState);
+ $imageDestinationFile = sprintf(
+ "%s@%s:${atlasFileName}",
+ $vimCfg['user'],
+ $vimCfg['address']
+ );
+ $this->copyImageToAtlas($workerSSH, $imageSourceFile, $imageDestinationFile);
+ $this->uploadImageToGlance($atlasSSH, $imageName);
+ $atlasSSH->execute("rm -rf ${atlasFileName}");
+ }
+}
diff --git a/src/App/Service/AtlasManagerFactory.php b/src/App/Service/AtlasManagerFactory.php
new file mode 100644
index 0000000..2f47da5
--- /dev/null
+++ b/src/App/Service/AtlasManagerFactory.php
@@ -0,0 +1,18 @@
+get(ConfigProvider::class);
+ $envConfig = $appConfig->getEnvironmentConfig();
+ return new AtlasManager($envConfig);
+ }
+}
diff --git a/src/App/Service/Builder.php b/src/App/Service/Builder.php
index 745d4ce..e948ed1 100644
--- a/src/App/Service/Builder.php
+++ b/src/App/Service/Builder.php
@@ -4,24 +4,123 @@ declare(strict_types=1);
namespace App\Service;
+use App\Command\SharedStorage;
use App\Runner\SSH;
+use Doctrine\Common\Collections\ArrayCollection;
use Exception;
class Builder
{
- const PACKAGE_BUILDER_SCRIPT = "prepare_package.sh";
+ use SharedStorage;
+
+ const WORKFLOW_PACKAGE_BUILDER_SCRIPT = "prepare_package.sh";
+ const VNF_PACKAGE_CREATOR_SCRIPT = "vnfPackageCreator_mtas.py";
+
+ const FULL_PKG = "CXP9034815_1";
+ const WF_PGK = "CXP9034788_1";
+ const VNF_PGK_REPO_PATH = "/vnflcm-ext/current/vnf_package_repo";
+
+ /** @var ConfigProvider */
+ private $configProvider;
+
+ public function __construct(ConfigProvider $configProvider, ArrayCollection $sharedStorage)
+ {
+ $this->configProvider = $configProvider;
+ $this->sharedStorage = $sharedStorage;
+ }
/**
- * @param $host
- * @param $path
- * @return string Generated filename on remote host
+ * @param SSH $ssh
+ * @param string $path
+ * @param string $branch
* @throws Exception
*/
- public function buildRemotePackage($host, $path): string
+ private function checkoutBranch(SSH $ssh, string $path, string $branch)
+ {
+ $ssh->execute("cd ${path} && git fetch origin && git checkout ${branch}");
+ }
+
+ /**
+ * @param string $host
+ * @param string $path
+ * @param string|null $branch
+ * @return string
+ * @throws Exception
+ */
+ public function buildRemotePackage(string $host, string $path, ?string $branch = null): string
{
$runner = new SSH($host);
- $out = $runner->execute(sprintf("%s/%s", $path, self::PACKAGE_BUILDER_SCRIPT));
+ if ($branch) {
+ $this->checkoutBranch($runner, $path, $branch);
+ }
+ $out = $runner->execute(sprintf("%s/%s", $path, self::WORKFLOW_PACKAGE_BUILDER_SCRIPT));
$lines = explode("\n", trim($out));
return array_pop($lines);
}
+
+ /**
+ * @param string $host
+ * @param string $imageStore
+ * @param string $rState
+ * @param string $node
+ * @param string $package
+ * @return string
+ * @throws Exception
+ */
+ public function createOnboardPackage(string $host, string $imageStore, string $rState, string $node, string $package): string
+ {
+ $swDirectory = "${imageStore}/${rState}/uncompressed";
+ $ssh = new SSH($host);
+ $workDir = trim($ssh->execute("mktemp -d"));
+ $this->saveToShared("tmp-dir", $workDir);
+ $packageName = basename($package);
+ preg_match(sprintf("/%s-(R[0-9]+[A-Z]+[0-9]+)\.tar\.gz/", self::FULL_PKG), $packageName, $matches);
+ $rState = $matches[1];
+ $ssh->execute("mv ${package} ${workDir}");
+ $ssh->execute("tar -xzf ${workDir}/${packageName} -C ${workDir}");
+ $ssh->execute(sprintf("tar -xzf ${workDir}/%s-${rState}.tar.gz -C ${workDir}", self::WF_PGK));
+ try {
+ $ssh->execute("ls -l ${swDirectory}/prepareHot.bash");
+ } catch(Exception $_) {
+ return $ssh->execute(sprintf(
+ "cd ${workDir} && ./%s -sw %s -hf %s -wf . -i %s 2>&1",
+ self::VNF_PACKAGE_CREATOR_SCRIPT,
+ $swDirectory,
+ sprintf("$swDirectory/%s/%s", TemplateGenerator::GENERATED_HOT_DIR, TemplateGenerator::APP_STACK_DIR),
+ $node
+ ));
+ }
+ $cmd = sprintf(
+ "cd ${workDir} && ./%s -sw %s -wf . -i %s 2>&1",
+ self::VNF_PACKAGE_CREATOR_SCRIPT,
+ $swDirectory,
+ $node
+ );
+ var_dump($cmd);
+ try {
+ return $ssh->execute($cmd);
+ } catch (Exception $_) {
+ throw new Exception("Couldn't create on-board package! Mismatching Workflow-MTAS packages?");
+ }
+ }
+
+ /**
+ * @param string $host
+ * @param string $node
+ * @param string $package
+ * @throws Exception
+ */
+ public function onboardPackage(string $host, string $node, string $package): void
+ {
+ $envConfig = $this->configProvider->getEnvironmentConfig();
+ $lcmConfig = $envConfig['node'][$node]['vnf-lcm'];
+ $lcmUri = sprintf("%s@%s", $lcmConfig['user'], $lcmConfig['address']);
+ $pkgName = basename($package);
+
+ $runner = new SSH($host);
+ $sshOptions = "-o StrictHostKeyChecking=no";
+ $runner->execute(sprintf("scp $sshOptions $package $lcmUri:%s/", self::VNF_PGK_REPO_PATH));
+ $runner->execute(sprintf("ssh $sshOptions $lcmUri 'cd %s && unzip -o $pkgName'", self::VNF_PGK_REPO_PATH));
+// $runner->execute(sprintf("ssh $sshOptions $lcmUri 'rm -f %s/$pkgName'", self::VNF_PGK_REPO_PATH));
+ }
}
diff --git a/src/App/Service/BuilderFactory.php b/src/App/Service/BuilderFactory.php
index 436c77b..9013b37 100644
--- a/src/App/Service/BuilderFactory.php
+++ b/src/App/Service/BuilderFactory.php
@@ -4,12 +4,17 @@ declare(strict_types=1);
namespace App\Service;
+use Doctrine\Common\Collections\ArrayCollection;
use Interop\Container\ContainerInterface;
class BuilderFactory
{
public function __invoke(ContainerInterface $container): Builder
{
- return new Builder();
+ /** @var ConfigProvider $configProvider */
+ $configProvider = $container->get(ConfigProvider::class);
+ /** @var ArrayCollection $sharedStorage */
+ $sharedStorage = $container->get(ArrayCollection::class);
+ return new Builder($configProvider, $sharedStorage);
}
}
diff --git a/src/App/Service/Cleanup.php b/src/App/Service/Cleanup.php
new file mode 100644
index 0000000..3e44abe
--- /dev/null
+++ b/src/App/Service/Cleanup.php
@@ -0,0 +1,33 @@
+configProvider = $configProvider;
+ }
+
+ /**
+ * @param $host
+ * @param $imageStore
+ * @param $rState
+ * @param $tmpDir
+ * @throws Exception
+ */
+ public function cleanup($host, $imageStore, $rState, $tmpDir)
+ {
+ $ssh = new SSH($host);
+ $ssh->execute("rm -rf ${imageStore}/${rState}/uncompressed");
+ $ssh->execute("rm -rf ${tmpDir}");
+ }
+}
diff --git a/src/App/Service/CleanupFactory.php b/src/App/Service/CleanupFactory.php
new file mode 100644
index 0000000..98790c6
--- /dev/null
+++ b/src/App/Service/CleanupFactory.php
@@ -0,0 +1,17 @@
+get(ConfigProvider::class);
+ return new Cleanup($configProvider);
+ }
+}
diff --git a/src/App/Service/ConfigProvider.php b/src/App/Service/ConfigProvider.php
index 5537fa0..ab5d9cb 100644
--- a/src/App/Service/ConfigProvider.php
+++ b/src/App/Service/ConfigProvider.php
@@ -47,18 +47,18 @@ class ConfigProvider
throw new InvalidArgumentException("Couldn't locate $filename");
}
- private function readConfigFile($configFile): ?iterable
+ private function readConfigFile($configFile): ?array
{
$configFile = $this->findConfigFile($configFile);
return Yaml::parseFile($configFile);
}
- public function getEnvironmentConfig(): ?iterable
+ public function getEnvironmentConfig(): ?array
{
return $this->readConfigFile($this->envFile);
}
- public function getTaskConfig(): ?iterable
+ public function getTaskConfig(): ?array
{
return $this->readConfigFile($this->taskFile);
}
diff --git a/src/App/Service/TemplateGenerator.php b/src/App/Service/TemplateGenerator.php
new file mode 100644
index 0000000..2154760
--- /dev/null
+++ b/src/App/Service/TemplateGenerator.php
@@ -0,0 +1,160 @@
+envConfig = $envConfig;
+ $this->taskConfig = $taskConfig;
+ }
+
+ /**
+ * @param string $template
+ * @param array $data
+ * @return string
+ * @throws LoaderError
+ * @throws RuntimeError
+ * @throws SyntaxError
+ */
+ private function fillJinjaTemplate(string $template, array $data): string
+ {
+ $twig = new Environment(new ArrayLoader(['env' => $template]));
+ return $twig->render('env', $data);
+ }
+
+ /**
+ * @param SSH $ssh
+ * @param string $envFile
+ * @param string $node
+ * @param string $key
+ * @throws Exception
+ */
+ private function fillEnv(SSH $ssh, string $envFile, string $node, string $key)
+ {
+ $fileContents = $ssh->readFile($envFile);
+ $unfilledEnv = Yaml::parse($fileContents);
+ $mergedConfig = $this->envConfig['node'][$node]['env']['shared'] + $this->envConfig['node'][$node]['env'][$key];
+ foreach ($unfilledEnv['parameters'] as $key => &$value) {
+ if (array_key_exists($key, $mergedConfig)) {
+ $value = $mergedConfig[$key];
+ }
+ }
+ $ssh->saveFile($envFile, Yaml::dump($unfilledEnv, 2, 4, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE));
+ }
+
+ /**
+ * @param SSH $ssh
+ * @param string $envFile
+ * @param string $node
+ * @throws LoaderError
+ * @throws RuntimeError
+ * @throws SyntaxError
+ * @throws Exception
+ */
+ private function prefillJinjaEnv(SSH $ssh, string $envFile, string $node)
+ {
+ $unfilledEnv = $ssh->readFile($envFile);
+ $data = $this->envConfig['node'][$node]['env']['shared'] + $this->envConfig['node'][$node]['env']['jinja'];
+ $filledTemplate = $this->fillJinjaTemplate($unfilledEnv, $data);
+ $ssh->saveFile($envFile, $filledTemplate);
+ }
+
+ /**
+ * @param SSH $ssh
+ * @param string $workDir
+ * @param string $node
+ * @throws Exception
+ */
+ private function generateLegacyTemplates(SSH $ssh, string $workDir, string $node)
+ {
+ $params = [];
+ foreach($this->envConfig['node'][$node]['template-params']['legacy'] as $k => $v) {
+ $params[] = "$k $v";
+ }
+ $ssh->execute(sprintf(
+ "cd ${workDir} && ./%s %s",
+ self::LEGACY_GENERATOR_SCRIPT,
+ implode(" ", $params)
+ ));
+ $this->fillEnv(
+ $ssh,
+ sprintf("$workDir/%s", self::LEGACY_ENV_FILE),
+ $node,
+ 'legacy'
+ );
+ }
+
+ /**
+ * @param SSH $ssh
+ * @param string $workDir
+ * @param string $node
+ * @throws Exception
+ */
+ private function generateJinjaTemplates(SSH $ssh, string $workDir, string $node)
+ {
+ $fileContents = $ssh->readFile(sprintf("%s/%s", $workDir, self::CONTEXT_TEMPLATE_FILE));
+ $filledContext = $this->fillJinjaTemplate(
+ $fileContents,
+ $this->envConfig['node'][$node]['template-params']['jinja']
+ );
+ $ssh->saveFile("${workDir}/" . self::FILLED_CONTEXT_FILE, $filledContext);
+
+ $ssh->execute(sprintf(
+ "${workDir}/%s $workDir/%s $workDir/%s",
+ self::JINJA_GENERATOR_SCRIPT,
+ self::GENERATED_HOT_DIR,
+ self::FILLED_CONTEXT_FILE));
+
+ $envFile = sprintf("$workDir/%s/%s/%s", self::GENERATED_HOT_DIR, self::APP_STACK_DIR, self::JINJA_ENV_FILE);
+ $this->prefillJinjaEnv($ssh, $envFile, $node);
+ $this->fillEnv($ssh, $envFile, $node, 'jinja');
+ }
+
+ /**
+ * @param string $host
+ * @param string $imageDir
+ * @param string $rState
+ * @param string $node
+ * @throws Exception
+ */
+ public function generateTemplates(string $host, string $imageDir, string $rState, string $node)
+ {
+ $workDir = "${imageDir}/${rState}/uncompressed";
+ $ssh = new SSH($host);
+ try {
+ $ssh->execute("ls -1 $workDir/" . self::LEGACY_GENERATOR_SCRIPT);
+ $this->generateLegacyTemplates($ssh, $workDir, $node);
+ } catch (Exception $_) {
+ $this->generateJinjaTemplates($ssh, $workDir, $node);
+ }
+ }
+}
diff --git a/src/App/Service/TemplateGeneratorFactory.php b/src/App/Service/TemplateGeneratorFactory.php
new file mode 100644
index 0000000..8564945
--- /dev/null
+++ b/src/App/Service/TemplateGeneratorFactory.php
@@ -0,0 +1,19 @@
+get(ConfigProvider::class);
+ $envConfig = $configProvider->getEnvironmentConfig();
+ $taskConfig = $configProvider->getTaskConfig();
+ return new TemplateGenerator($envConfig, $taskConfig);
+ }
+}