From aaa5e73e979cad6baa86b700daedf8955a328205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miles=20St=C3=B6tzner?= Date: Tue, 17 Sep 2024 23:36:27 +0200 Subject: [PATCH] fix quality command --- .../lib/agents/falco.agent.yaml | 1163 +- .../lib/agents/node.agent.yaml | 2770 +- .../lib/agents/promtail.agent.yaml | 1163 +- .../lib/boutique/advertisement.component.yaml | 2813 +- .../lib/boutique/analytics.component.yaml | 2849 +- .../lib/boutique/cart.component.yaml | 2802 +- .../lib/boutique/checkout.component.yaml | 2723 +- .../lib/boutique/currency.component.yaml | 2813 +- .../lib/boutique/email.component.yaml | 2813 +- .../lib/boutique/frontend.component.yaml | 2754 +- .../lib/boutique/payment.component.yaml | 2849 +- .../lib/boutique/product.component.yaml | 2813 +- .../boutique/recommendation.component.yaml | 2824 +- .../lib/boutique/shipping.component.yaml | 2813 +- .../lib/technology-rules.yaml | 399 +- .../lib/tosca-vintner-profile-core.yaml | 3693 ++- .../lib/tosca-vintner-profile-extended.yaml | 25116 ++++++++++++--- .../lib/shop.component.yaml | 2516 +- .../lib/technology-rules.yaml | 307 +- .../lib/tosca-vintner-profile-core.yaml | 2853 +- .../lib/tosca-vintner-profile-extended.yaml | 25161 +++++++++++----- .../scripts/quality.sh | 7 +- src/controller/study/technology.ts | 26 +- src/controller/template/quality.ts | 31 +- src/resolver/result.ts | 48 +- 25 files changed, 78601 insertions(+), 17518 deletions(-) diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/falco.agent.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/falco.agent.yaml index 3d4112580f..37c20ed82e 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/falco.agent.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/falco.agent.yaml @@ -27,6 +27,372 @@ node_types: # ################################################################ + falco.agent~software.application#apt.package::ansible@*->local.machine: + derived_from: falco.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + falco.agent~software.application#apt.package::terraform@*->local.machine: + derived_from: falco.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-falco.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-falco.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-falco.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-falco.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-falco.agent.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-falco.agent.sh + - sudo bash /tmp/configure-falco.agent.sh + - sudo bash /tmp/start-falco.agent.sh + - inline: + - sudo bash /tmp/stop-falco.agent.sh + - sudo bash /tmp/delete-falco.agent.sh + when: destroy falco.agent~software.application#apt.package::ansible@*->remote.machine: derived_from: falco.agent metadata: @@ -159,6 +525,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -190,6 +560,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -249,7 +623,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - falco.agent~software.application#apt.archive::terraform@*->remote.machine: + falco.agent~software.application#apt.package::terraform@*->remote.machine: derived_from: falco.agent metadata: vintner_generated: 'true' @@ -334,14 +708,6 @@ node_types: EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-falco.agent {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -446,20 +812,12 @@ node_types: - sudo bash /tmp/stop-falco.agent.sh - sudo bash /tmp/delete-falco.agent.sh when: destroy - falco.agent~software.application#tar.archive::ansible@*->remote.machine: + falco.agent~software.application#tar.archive::ansible@*->local.machine: derived_from: falco.agent metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -474,14 +832,16 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - name: wait for ssh wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -523,16 +883,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -554,16 +908,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -589,9 +937,389 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + falco.agent~software.application#tar.archive::terraform@*->local.machine: + derived_from: falco.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-falco.agent + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-falco.agent {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-falco.agent -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-falco.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-falco.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-falco.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-falco.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-falco.agent.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-falco.agent.sh + - sudo bash /tmp/configure-falco.agent.sh + - sudo bash /tmp/start-falco.agent.sh + - inline: + - sudo bash /tmp/stop-falco.agent.sh + - sudo bash /tmp/delete-falco.agent.sh + when: destroy + falco.agent~software.application#tar.archive::ansible@*->remote.machine: + derived_from: falco.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' stop: implementation: @@ -846,6 +1574,358 @@ node_types: - sudo bash /tmp/stop-falco.agent.sh - sudo bash /tmp/delete-falco.agent.sh when: destroy + falco.agent~software.application#zip.archive::ansible@*->local.machine: + derived_from: falco.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + falco.agent~software.application#zip.archive::terraform@*->local.machine: + derived_from: falco.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-falco.agent + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-falco.agent {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-falco.agent -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-falco.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-falco.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-falco.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-falco.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-falco.agent.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-falco.agent.sh + - sudo bash /tmp/configure-falco.agent.sh + - sudo bash /tmp/start-falco.agent.sh + - inline: + - sudo bash /tmp/stop-falco.agent.sh + - sudo bash /tmp/delete-falco.agent.sh + when: destroy falco.agent~software.application#zip.archive::ansible@*->remote.machine: derived_from: falco.agent metadata: @@ -896,12 +1976,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/node.agent.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/node.agent.yaml index 07311c0eaa..3a4f97b106 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/node.agent.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/node.agent.yaml @@ -25,6 +25,150 @@ node_types: # ################################################################ + node.agent~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: {} + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + node.agent~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: {} + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: {} + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + node.agent~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: [] + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' node.agent~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: node.agent metadata: @@ -157,7 +301,7 @@ node_types: image: '{{ ".artifacts::docker_image::file" | eval }}' network_mode: host environment: {} - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -739,20 +883,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - node.agent~service.application#tar.archive::ansible@*->remote.machine: + node.agent~service.application#tar.archive::ansible@*->local.machine: derived_from: node.agent metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -767,14 +903,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -837,21 +969,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -868,21 +992,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -897,27 +1013,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -938,21 +1056,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -969,6 +1079,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -976,31 +1090,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - node.agent~service.application#tar.archive::terraform@*->remote.machine: + node.agent~service.application#tar.archive::terraform@*->local.machine: derived_from: node.agent metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1022,146 +1116,156 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-node.agent + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-node.agent {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-node.agent -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-node.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-node.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-node.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-node.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-node.agent.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-node.agent - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-node.agent {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-node.agent -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-node.agent.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-node.agent.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-node.agent.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-node.agent.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-node.agent.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-node.agent.sh - sudo bash /tmp/configure-node.agent.sh @@ -1170,7 +1274,7 @@ node_types: - sudo bash /tmp/stop-node.agent.sh - sudo bash /tmp/delete-node.agent.sh when: destroy - node.agent~service.application#zip.archive::ansible@*->remote.machine: + node.agent~service.application#tar.archive::ansible@*->remote.machine: derived_from: node.agent metadata: vintner_generated: 'true' @@ -1206,26 +1310,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1331,6 +1432,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1352,6 +1459,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1403,6 +1514,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1410,15 +1525,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - node.agent~service.application#zip.archive::terraform@*->remote.machine: + node.agent~service.application#tar.archive::terraform@*->remote.machine: derived_from: node.agent metadata: vintner_generated: 'true' @@ -1465,9 +1576,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-node.agent - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1494,12 +1605,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-node.agent {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-node.agent {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-node.agent -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-node.agent -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1604,24 +1715,20 @@ node_types: - sudo bash /tmp/stop-node.agent.sh - sudo bash /tmp/delete-node.agent.sh when: destroy - node.agent~service.application#zip.archive::ansible@gcp.appengine: + node.agent~service.application#zip.archive::ansible@*->local.machine: derived_from: node.agent metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1632,90 +1739,1195 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: {} - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet - args: - executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + dest: '{{ SELF.application_directory }}/.env' + content: '' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: - application_address: '{{ outputs.application_address | trim }}' - application_endpoint: '{{ outputs.application_endpoint | trim }}' - outputs: - application_address: - application_endpoint: - delete: + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - node.agent~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + node.agent~service.application#zip.archive::terraform@*->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-node.agent + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-node.agent {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-node.agent -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-node.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-node.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-node.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-node.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-node.agent.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-node.agent.sh + - sudo bash /tmp/configure-node.agent.sh + - sudo bash /tmp/start-node.agent.sh + - inline: + - sudo bash /tmp/stop-node.agent.sh + - sudo bash /tmp/delete-node.agent.sh + when: destroy + node.agent~service.application#zip.archive::ansible@*->remote.machine: derived_from: node.agent metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + node.agent~service.application#zip.archive::terraform@*->remote.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-node.agent + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-node.agent {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-node.agent -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-node.agent.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-node.agent.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-node.agent.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-node.agent.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-node.agent.sh + remote-exec: + - inline: + - sudo bash /tmp/create-node.agent.sh + - sudo bash /tmp/configure-node.agent.sh + - sudo bash /tmp/start-node.agent.sh + - inline: + - sudo bash /tmp/stop-node.agent.sh + - sudo bash /tmp/delete-node.agent.sh + when: destroy + node.agent~service.application#zip.archive::ansible@gcp.appengine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: {} + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address | trim }}' + application_endpoint: '{{ outputs.application_endpoint | trim }}' + outputs: + application_address: + application_endpoint: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + node.agent~service.application#zip.archive::terraform@gcp.appengine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' + resource: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: {} + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + node.agent~software.application#apt.package::ansible@*->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + node.agent~software.application#apt.package::terraform@*->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1726,62 +2938,167 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: {} - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-node.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-node.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-node.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-node.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-node.agent.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-node.agent.sh + - sudo bash /tmp/configure-node.agent.sh + - sudo bash /tmp/start-node.agent.sh + - inline: + - sudo bash /tmp/stop-node.agent.sh + - sudo bash /tmp/delete-node.agent.sh + when: destroy node.agent~software.application#apt.package::ansible@*->remote.machine: derived_from: node.agent metadata: @@ -1914,6 +3231,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -1945,6 +3266,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2004,7 +3329,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - node.agent~software.application#apt.archive::terraform@*->remote.machine: + node.agent~software.application#apt.package::terraform@*->remote.machine: derived_from: node.agent metadata: vintner_generated: 'true' @@ -2089,14 +3414,6 @@ node_types: EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-node.agent {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2189,10 +3506,372 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-node.agent.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-node.agent.sh + remote-exec: + - inline: + - sudo bash /tmp/create-node.agent.sh + - sudo bash /tmp/configure-node.agent.sh + - sudo bash /tmp/start-node.agent.sh + - inline: + - sudo bash /tmp/stop-node.agent.sh + - sudo bash /tmp/delete-node.agent.sh + when: destroy + node.agent~software.application#tar.archive::ansible@*->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + node.agent~software.application#tar.archive::terraform@*->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-node.agent + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-node.agent {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-node.agent -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-node.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-node.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-node.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-node.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-node.agent.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - sudo bash /tmp/create-node.agent.sh - sudo bash /tmp/configure-node.agent.sh @@ -2601,6 +4280,358 @@ node_types: - sudo bash /tmp/stop-node.agent.sh - sudo bash /tmp/delete-node.agent.sh when: destroy + node.agent~software.application#zip.archive::ansible@*->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + node.agent~software.application#zip.archive::terraform@*->local.machine: + derived_from: node.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-node.agent + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-node.agent {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-node.agent -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-node.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-node.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-node.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-node.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-node.agent.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-node.agent.sh + - sudo bash /tmp/configure-node.agent.sh + - sudo bash /tmp/start-node.agent.sh + - inline: + - sudo bash /tmp/stop-node.agent.sh + - sudo bash /tmp/delete-node.agent.sh + when: destroy node.agent~software.application#zip.archive::ansible@*->remote.machine: derived_from: node.agent metadata: @@ -2651,12 +4682,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/promtail.agent.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/promtail.agent.yaml index c79345c7e5..68b0323b84 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/promtail.agent.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/agents/promtail.agent.yaml @@ -25,6 +25,372 @@ node_types: # ################################################################ + promtail.agent~software.application#apt.package::ansible@*->local.machine: + derived_from: promtail.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + promtail.agent~software.application#apt.package::terraform@*->local.machine: + derived_from: promtail.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-promtail.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-promtail.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-promtail.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-promtail.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-promtail.agent.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-promtail.agent.sh + - sudo bash /tmp/configure-promtail.agent.sh + - sudo bash /tmp/start-promtail.agent.sh + - inline: + - sudo bash /tmp/stop-promtail.agent.sh + - sudo bash /tmp/delete-promtail.agent.sh + when: destroy promtail.agent~software.application#apt.package::ansible@*->remote.machine: derived_from: promtail.agent metadata: @@ -157,6 +523,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -188,6 +558,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -247,7 +621,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - promtail.agent~software.application#apt.archive::terraform@*->remote.machine: + promtail.agent~software.application#apt.package::terraform@*->remote.machine: derived_from: promtail.agent metadata: vintner_generated: 'true' @@ -332,14 +706,6 @@ node_types: EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-promtail.agent {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -444,20 +810,12 @@ node_types: - sudo bash /tmp/stop-promtail.agent.sh - sudo bash /tmp/delete-promtail.agent.sh when: destroy - promtail.agent~software.application#tar.archive::ansible@*->remote.machine: + promtail.agent~software.application#tar.archive::ansible@*->local.machine: derived_from: promtail.agent metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -472,14 +830,16 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - name: wait for ssh wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -521,16 +881,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -552,16 +906,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -587,9 +935,389 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + promtail.agent~software.application#tar.archive::terraform@*->local.machine: + derived_from: promtail.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-promtail.agent + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-promtail.agent {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-promtail.agent -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-promtail.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-promtail.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-promtail.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-promtail.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-promtail.agent.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-promtail.agent.sh + - sudo bash /tmp/configure-promtail.agent.sh + - sudo bash /tmp/start-promtail.agent.sh + - inline: + - sudo bash /tmp/stop-promtail.agent.sh + - sudo bash /tmp/delete-promtail.agent.sh + when: destroy + promtail.agent~software.application#tar.archive::ansible@*->remote.machine: + derived_from: promtail.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' stop: implementation: @@ -844,6 +1572,358 @@ node_types: - sudo bash /tmp/stop-promtail.agent.sh - sudo bash /tmp/delete-promtail.agent.sh when: destroy + promtail.agent~software.application#zip.archive::ansible@*->local.machine: + derived_from: promtail.agent + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + promtail.agent~software.application#zip.archive::terraform@*->local.machine: + derived_from: promtail.agent + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-promtail.agent + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-promtail.agent {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-promtail.agent -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-promtail.agent.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-promtail.agent.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-promtail.agent.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-promtail.agent.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-promtail.agent.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-promtail.agent.sh + - sudo bash /tmp/configure-promtail.agent.sh + - sudo bash /tmp/start-promtail.agent.sh + - inline: + - sudo bash /tmp/stop-promtail.agent.sh + - sudo bash /tmp/delete-promtail.agent.sh + when: destroy promtail.agent~software.application#zip.archive::ansible@*->remote.machine: derived_from: promtail.agent metadata: @@ -894,12 +1974,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/advertisement.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/advertisement.component.yaml index 79fd4a92d5..9b94444a28 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/advertisement.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/advertisement.component.yaml @@ -62,6 +62,158 @@ node_types: # ################################################################ + advertisement.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + advertisement.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + advertisement.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' advertisement.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: advertisement.component metadata: @@ -200,7 +352,7 @@ node_types: environment: PORT: '"{{ SELF.application_port }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -810,20 +962,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - advertisement.component~service.application#tar.archive::ansible@*->remote.machine: + advertisement.component~service.application#tar.archive::ansible@*->local.machine: derived_from: advertisement.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -838,14 +982,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -910,21 +1050,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -941,21 +1073,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -970,27 +1094,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1011,21 +1137,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1042,6 +1160,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1049,31 +1171,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - advertisement.component~service.application#tar.archive::terraform@*->remote.machine: + advertisement.component~service.application#tar.archive::terraform@*->local.machine: derived_from: advertisement.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1095,147 +1197,157 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-advertisement.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-advertisement.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-advertisement.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-advertisement.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-advertisement.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-advertisement.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-advertisement.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-advertisement.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-advertisement.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-advertisement.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-advertisement.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-advertisement.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-advertisement.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-advertisement.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-advertisement.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-advertisement.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-advertisement.component.sh - sudo bash /tmp/configure-advertisement.component.sh @@ -1244,7 +1356,7 @@ node_types: - sudo bash /tmp/stop-advertisement.component.sh - sudo bash /tmp/delete-advertisement.component.sh when: destroy - advertisement.component~service.application#zip.archive::ansible@*->remote.machine: + advertisement.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: advertisement.component metadata: vintner_generated: 'true' @@ -1280,26 +1392,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1407,6 +1516,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1428,6 +1543,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1479,6 +1598,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1486,15 +1609,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - advertisement.component~service.application#zip.archive::terraform@*->remote.machine: + advertisement.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: advertisement.component metadata: vintner_generated: 'true' @@ -1541,9 +1660,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-advertisement.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1571,12 +1690,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-advertisement.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-advertisement.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-advertisement.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-advertisement.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1681,27 +1800,20 @@ node_types: - sudo bash /tmp/stop-advertisement.component.sh - sudo bash /tmp/delete-advertisement.component.sh when: destroy - advertisement.component~service.application#zip.archive::ansible@gcp.appengine: + advertisement.component~service.application#zip.archive::ansible@*->local.machine: derived_from: advertisement.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1712,94 +1824,1209 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet - args: - executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' - args: - executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + advertisement.component~service.application#zip.archive::terraform@*->local.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-advertisement.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-advertisement.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-advertisement.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-advertisement.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-advertisement.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-advertisement.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-advertisement.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-advertisement.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-advertisement.component.sh + - sudo bash /tmp/configure-advertisement.component.sh + - sudo bash /tmp/start-advertisement.component.sh + - inline: + - sudo bash /tmp/stop-advertisement.component.sh + - sudo bash /tmp/delete-advertisement.component.sh + when: destroy + advertisement.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + advertisement.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-advertisement.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-advertisement.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-advertisement.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-advertisement.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-advertisement.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-advertisement.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-advertisement.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-advertisement.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-advertisement.component.sh + - sudo bash /tmp/configure-advertisement.component.sh + - sudo bash /tmp/start-advertisement.component.sh + - inline: + - sudo bash /tmp/stop-advertisement.component.sh + - sudo bash /tmp/delete-advertisement.component.sh + when: destroy + advertisement.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: application_address: '{{ outputs.application_address | trim }}' application_endpoint: '{{ outputs.application_endpoint | trim }}' outputs: application_address: application_endpoint: - delete: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + advertisement.component~service.application#zip.archive::terraform@gcp.appengine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' + resource: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + advertisement.component~software.application#apt.package::ansible@*->local.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - args: executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - advertisement.component~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + advertisement.component~software.application#apt.package::terraform@*->local.machine: derived_from: advertisement.component metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1810,63 +3037,168 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-advertisement.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-advertisement.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-advertisement.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-advertisement.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-advertisement.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-advertisement.component.sh + - sudo bash /tmp/configure-advertisement.component.sh + - sudo bash /tmp/start-advertisement.component.sh + - inline: + - sudo bash /tmp/stop-advertisement.component.sh + - sudo bash /tmp/delete-advertisement.component.sh + when: destroy advertisement.component~software.application#apt.package::ansible@*->remote.machine: derived_from: advertisement.component metadata: @@ -1999,6 +3331,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2030,6 +3366,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2089,7 +3429,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - advertisement.component~software.application#apt.archive::terraform@*->remote.machine: + advertisement.component~software.application#apt.package::terraform@*->remote.machine: derived_from: advertisement.component metadata: vintner_generated: 'true' @@ -2175,14 +3515,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-advertisement.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2275,10 +3607,375 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-advertisement.component.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-advertisement.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-advertisement.component.sh + - sudo bash /tmp/configure-advertisement.component.sh + - sudo bash /tmp/start-advertisement.component.sh + - inline: + - sudo bash /tmp/stop-advertisement.component.sh + - sudo bash /tmp/delete-advertisement.component.sh + when: destroy + advertisement.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + advertisement.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-advertisement.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-advertisement.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-advertisement.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-advertisement.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-advertisement.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-advertisement.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-advertisement.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-advertisement.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - sudo bash /tmp/create-advertisement.component.sh - sudo bash /tmp/configure-advertisement.component.sh @@ -2690,6 +4387,361 @@ node_types: - sudo bash /tmp/stop-advertisement.component.sh - sudo bash /tmp/delete-advertisement.component.sh when: destroy + advertisement.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + advertisement.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: advertisement.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-advertisement.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-advertisement.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-advertisement.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-advertisement.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-advertisement.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-advertisement.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-advertisement.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-advertisement.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-advertisement.component.sh + - sudo bash /tmp/configure-advertisement.component.sh + - sudo bash /tmp/start-advertisement.component.sh + - inline: + - sudo bash /tmp/stop-advertisement.component.sh + - sudo bash /tmp/delete-advertisement.component.sh + when: destroy advertisement.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: advertisement.component metadata: @@ -2740,12 +4792,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/analytics.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/analytics.component.yaml index 635a96c1df..666bb6bf84 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/analytics.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/analytics.component.yaml @@ -69,6 +69,166 @@ node_types: # ################################################################ + analytics.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' + RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + analytics.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' + RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' + RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + analytics.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - CHECKOUT_SERVICE_ADDR={{ SELF.CHECKOUT_SERVICE_ADDR }} + - RECOMMENDATION_SERVICE_ADDR={{ SELF.RECOMMENDATION_SERVICE_ADDR }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' analytics.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: analytics.component metadata: @@ -213,7 +373,7 @@ node_types: CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -849,20 +1009,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - analytics.component~service.application#tar.archive::ansible@*->remote.machine: + analytics.component~service.application#tar.archive::ansible@*->local.machine: derived_from: analytics.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -877,14 +1029,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -951,21 +1099,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -982,21 +1122,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -1011,27 +1143,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1052,21 +1186,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1083,6 +1209,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1090,31 +1220,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - analytics.component~service.application#tar.archive::terraform@*->remote.machine: + analytics.component~service.application#tar.archive::terraform@*->local.machine: derived_from: analytics.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1136,149 +1246,159 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-analytics.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-analytics.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-analytics.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-analytics.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-analytics.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-analytics.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-analytics.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-analytics.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-analytics.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" - RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-analytics.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-analytics.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-analytics.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-analytics.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-analytics.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-analytics.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-analytics.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-analytics.component.sh - sudo bash /tmp/configure-analytics.component.sh @@ -1287,7 +1407,7 @@ node_types: - sudo bash /tmp/stop-analytics.component.sh - sudo bash /tmp/delete-analytics.component.sh when: destroy - analytics.component~service.application#zip.archive::ansible@*->remote.machine: + analytics.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: analytics.component metadata: vintner_generated: 'true' @@ -1323,26 +1443,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1452,6 +1569,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1473,6 +1596,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1524,6 +1651,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1531,15 +1662,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - analytics.component~service.application#zip.archive::terraform@*->remote.machine: + analytics.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: analytics.component metadata: vintner_generated: 'true' @@ -1586,9 +1713,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-analytics.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1618,12 +1745,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-analytics.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-analytics.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-analytics.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-analytics.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1728,27 +1855,20 @@ node_types: - sudo bash /tmp/stop-analytics.component.sh - sudo bash /tmp/delete-analytics.component.sh when: destroy - analytics.component~service.application#zip.archive::ansible@gcp.appengine: + analytics.component~service.application#zip.archive::ansible@*->local.machine: derived_from: analytics.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1759,96 +1879,1221 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: - CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' - RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet - args: - executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: - application_address: '{{ outputs.application_address | trim }}' - application_endpoint: '{{ outputs.application_endpoint | trim }}' - outputs: - application_address: - application_endpoint: - delete: + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - analytics.component~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + analytics.component~service.application#zip.archive::terraform@*->local.machine: derived_from: analytics.component metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-analytics.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-analytics.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-analytics.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-analytics.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-analytics.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-analytics.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-analytics.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-analytics.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-analytics.component.sh + - sudo bash /tmp/configure-analytics.component.sh + - sudo bash /tmp/start-analytics.component.sh + - inline: + - sudo bash /tmp/stop-analytics.component.sh + - sudo bash /tmp/delete-analytics.component.sh + when: destroy + analytics.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + analytics.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-analytics.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-analytics.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-analytics.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-analytics.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-analytics.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-analytics.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-analytics.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-analytics.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-analytics.component.sh + - sudo bash /tmp/configure-analytics.component.sh + - sudo bash /tmp/start-analytics.component.sh + - inline: + - sudo bash /tmp/stop-analytics.component.sh + - sudo bash /tmp/delete-analytics.component.sh + when: destroy + analytics.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' + RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address | trim }}' + application_endpoint: '{{ outputs.application_endpoint | trim }}' + outputs: + application_address: + application_endpoint: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + analytics.component~service.application#zip.archive::terraform@gcp.appengine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' + resource: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' + RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + analytics.component~software.application#apt.package::ansible@*->local.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + analytics.component~software.application#apt.package::terraform@*->local.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1859,65 +3104,170 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' - RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-analytics.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-analytics.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-analytics.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-analytics.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-analytics.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-analytics.component.sh + - sudo bash /tmp/configure-analytics.component.sh + - sudo bash /tmp/start-analytics.component.sh + - inline: + - sudo bash /tmp/stop-analytics.component.sh + - sudo bash /tmp/delete-analytics.component.sh + when: destroy analytics.component~software.application#apt.package::ansible@*->remote.machine: derived_from: analytics.component metadata: @@ -2050,6 +3400,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2081,6 +3435,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2140,7 +3498,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - analytics.component~software.application#apt.archive::terraform@*->remote.machine: + analytics.component~software.application#apt.package::terraform@*->remote.machine: derived_from: analytics.component metadata: vintner_generated: 'true' @@ -2228,14 +3586,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-analytics.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2340,6 +3690,375 @@ node_types: - sudo bash /tmp/stop-analytics.component.sh - sudo bash /tmp/delete-analytics.component.sh when: destroy + analytics.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + analytics.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-analytics.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-analytics.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-analytics.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-analytics.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-analytics.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-analytics.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-analytics.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-analytics.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-analytics.component.sh + - sudo bash /tmp/configure-analytics.component.sh + - sudo bash /tmp/start-analytics.component.sh + - inline: + - sudo bash /tmp/stop-analytics.component.sh + - sudo bash /tmp/delete-analytics.component.sh + when: destroy analytics.component~software.application#tar.archive::ansible@*->remote.machine: derived_from: analytics.component metadata: @@ -2747,6 +4466,365 @@ node_types: - sudo bash /tmp/stop-analytics.component.sh - sudo bash /tmp/delete-analytics.component.sh when: destroy + analytics.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + analytics.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: analytics.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-analytics.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-analytics.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-analytics.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-analytics.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-analytics.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-analytics.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-analytics.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-analytics.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-analytics.component.sh + - sudo bash /tmp/configure-analytics.component.sh + - sudo bash /tmp/start-analytics.component.sh + - inline: + - sudo bash /tmp/stop-analytics.component.sh + - sudo bash /tmp/delete-analytics.component.sh + when: destroy analytics.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: analytics.component metadata: @@ -2797,12 +4875,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/cart.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/cart.component.yaml index b091cdc9a6..1aa431e67d 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/cart.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/cart.component.yaml @@ -90,6 +90,186 @@ node_types: # ################################################################ + cart.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + MYSQL_HOST: '"{{ SELF.mysql_host }}"' + MYSQL_PORT: '"{{ SELF.mysql_port }}"' + MYSQL_DATABASE: '"{{ SELF.mysql_database }}"' + MYSQL_USER: '"{{ SELF.mysql_user }}"' + MYSQL_PASSWORD: '"{{ SELF.mysql_password }}"' + MYSQL_TABLE: '"{{ SELF.mysql_table }}"' + MYSQL_SSL_MODE: '"{{ SELF.mysql_ssl_mode }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + cart.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + MYSQL_HOST: '"{{ SELF.mysql_host }}"' + MYSQL_PORT: '"{{ SELF.mysql_port }}"' + MYSQL_DATABASE: '"{{ SELF.mysql_database }}"' + MYSQL_USER: '"{{ SELF.mysql_user }}"' + MYSQL_PASSWORD: '"{{ SELF.mysql_password }}"' + MYSQL_TABLE: '"{{ SELF.mysql_table }}"' + MYSQL_SSL_MODE: '"{{ SELF.mysql_ssl_mode }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + MYSQL_HOST: '"{{ SELF.mysql_host }}"' + MYSQL_PORT: '"{{ SELF.mysql_port }}"' + MYSQL_DATABASE: '"{{ SELF.mysql_database }}"' + MYSQL_USER: '"{{ SELF.mysql_user }}"' + MYSQL_PASSWORD: '"{{ SELF.mysql_password }}"' + MYSQL_TABLE: '"{{ SELF.mysql_table }}"' + MYSQL_SSL_MODE: '"{{ SELF.mysql_ssl_mode }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + cart.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - MYSQL_HOST={{ SELF.mysql_host }} + - MYSQL_PORT={{ SELF.mysql_port }} + - MYSQL_DATABASE={{ SELF.mysql_database }} + - MYSQL_USER={{ SELF.mysql_user }} + - MYSQL_PASSWORD={{ SELF.mysql_password }} + - MYSQL_TABLE={{ SELF.mysql_table }} + - MYSQL_SSL_MODE={{ SELF.mysql_ssl_mode }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' cart.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: cart.component metadata: @@ -249,7 +429,7 @@ node_types: MYSQL_TABLE: '"{{ SELF.mysql_table }}"' MYSQL_SSL_MODE: '"{{ SELF.mysql_ssl_mode }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -950,20 +1130,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - cart.component~service.application#tar.archive::ansible@*->remote.machine: + cart.component~service.application#tar.archive::ansible@*->local.machine: derived_from: cart.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -978,14 +1150,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -1057,21 +1225,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -1088,21 +1248,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -1117,27 +1269,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1158,21 +1312,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1189,6 +1335,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1196,32 +1346,12 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - cart.component~service.application#tar.archive::terraform@*->remote.machine: + cart.component~service.application#tar.archive::terraform@*->local.machine: derived_from: cart.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - application_directory: + application_directory: type: string default: concat: @@ -1242,154 +1372,164 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-cart.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cart.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-cart.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-cart.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cart.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-cart.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-cart.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-cart.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-cart.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - MYSQL_HOST="{{ SELF.mysql_host }}" - MYSQL_PORT="{{ SELF.mysql_port }}" - MYSQL_DATABASE="{{ SELF.mysql_database }}" - MYSQL_USER="{{ SELF.mysql_user }}" - MYSQL_PASSWORD="{{ SELF.mysql_password }}" - MYSQL_TABLE="{{ SELF.mysql_table }}" - MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-cart.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-cart.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-cart.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-cart.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-cart.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-cart.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-cart.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-cart.component.sh - sudo bash /tmp/configure-cart.component.sh @@ -1398,7 +1538,7 @@ node_types: - sudo bash /tmp/stop-cart.component.sh - sudo bash /tmp/delete-cart.component.sh when: destroy - cart.component~service.application#zip.archive::ansible@*->remote.machine: + cart.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: cart.component metadata: vintner_generated: 'true' @@ -1434,26 +1574,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1568,6 +1705,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1589,6 +1732,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1640,6 +1787,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1647,15 +1798,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - cart.component~service.application#zip.archive::terraform@*->remote.machine: + cart.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: cart.component metadata: vintner_generated: 'true' @@ -1702,9 +1849,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-cart.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1739,12 +1886,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-cart.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cart.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-cart.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-cart.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1849,27 +1996,20 @@ node_types: - sudo bash /tmp/stop-cart.component.sh - sudo bash /tmp/delete-cart.component.sh when: destroy - cart.component~service.application#zip.archive::ansible@gcp.appengine: + cart.component~service.application#zip.archive::ansible@*->local.machine: derived_from: cart.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1880,28 +2020,909 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification - ansible.builtin.copy: + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + cart.component~service.application#zip.archive::terraform@*->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-cart.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cart.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-cart.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-cart.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cart.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-cart.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-cart.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-cart.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-cart.component.sh + - sudo bash /tmp/configure-cart.component.sh + - sudo bash /tmp/start-cart.component.sh + - inline: + - sudo bash /tmp/stop-cart.component.sh + - sudo bash /tmp/delete-cart.component.sh + when: destroy + cart.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + cart.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-cart.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cart.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-cart.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-cart.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-cart.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-cart.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-cart.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-cart.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-cart.component.sh + - sudo bash /tmp/configure-cart.component.sh + - sudo bash /tmp/start-cart.component.sh + - inline: + - sudo bash /tmp/stop-cart.component.sh + - sudo bash /tmp/delete-cart.component.sh + when: destroy + cart.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: dest: '{{ directory.path }}/app.yaml' content: '{{ manifest | to_yaml }}' vars: @@ -2006,49 +3027,423 @@ node_types: application_endpoint: - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - MYSQL_HOST: '"{{ SELF.mysql_host }}"' - MYSQL_PORT: '"{{ SELF.mysql_port }}"' - MYSQL_DATABASE: '"{{ SELF.mysql_database }}"' - MYSQL_USER: '"{{ SELF.mysql_user }}"' - MYSQL_PASSWORD: '"{{ SELF.mysql_password }}"' - MYSQL_TABLE: '"{{ SELF.mysql_table }}"' - MYSQL_SSL_MODE: '"{{ SELF.mysql_ssl_mode }}"' - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + MYSQL_HOST: '"{{ SELF.mysql_host }}"' + MYSQL_PORT: '"{{ SELF.mysql_port }}"' + MYSQL_DATABASE: '"{{ SELF.mysql_database }}"' + MYSQL_USER: '"{{ SELF.mysql_user }}"' + MYSQL_PASSWORD: '"{{ SELF.mysql_password }}"' + MYSQL_TABLE: '"{{ SELF.mysql_table }}"' + MYSQL_SSL_MODE: '"{{ SELF.mysql_ssl_mode }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + cart.component~software.application#apt.package::ansible@*->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + cart.component~software.application#apt.package::terraform@*->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-cart.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cart.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-cart.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-cart.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-cart.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-cart.component.sh + - sudo bash /tmp/configure-cart.component.sh + - sudo bash /tmp/start-cart.component.sh + - inline: + - sudo bash /tmp/stop-cart.component.sh + - sudo bash /tmp/delete-cart.component.sh + when: destroy cart.component~software.application#apt.package::ansible@*->remote.machine: derived_from: cart.component metadata: @@ -2181,6 +3576,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2212,6 +3611,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2271,7 +3674,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - cart.component~software.application#apt.archive::terraform@*->remote.machine: + cart.component~software.application#apt.package::terraform@*->remote.machine: derived_from: cart.component metadata: vintner_generated: 'true' @@ -2364,14 +3767,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-cart.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2476,6 +3871,385 @@ node_types: - sudo bash /tmp/stop-cart.component.sh - sudo bash /tmp/delete-cart.component.sh when: destroy + cart.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + cart.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-cart.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cart.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-cart.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-cart.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cart.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-cart.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-cart.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-cart.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-cart.component.sh + - sudo bash /tmp/configure-cart.component.sh + - sudo bash /tmp/start-cart.component.sh + - inline: + - sudo bash /tmp/stop-cart.component.sh + - sudo bash /tmp/delete-cart.component.sh + when: destroy cart.component~software.application#tar.archive::ansible@*->remote.machine: derived_from: cart.component metadata: @@ -2893,6 +4667,375 @@ node_types: - sudo bash /tmp/stop-cart.component.sh - sudo bash /tmp/delete-cart.component.sh when: destroy + cart.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + cart.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: cart.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-cart.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + MYSQL_HOST="{{ SELF.mysql_host }}" + MYSQL_PORT="{{ SELF.mysql_port }}" + MYSQL_DATABASE="{{ SELF.mysql_database }}" + MYSQL_USER="{{ SELF.mysql_user }}" + MYSQL_PASSWORD="{{ SELF.mysql_password }}" + MYSQL_TABLE="{{ SELF.mysql_table }}" + MYSQL_SSL_MODE="{{ SELF.mysql_ssl_mode }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cart.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-cart.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-cart.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cart.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-cart.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-cart.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-cart.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-cart.component.sh + - sudo bash /tmp/configure-cart.component.sh + - sudo bash /tmp/start-cart.component.sh + - inline: + - sudo bash /tmp/stop-cart.component.sh + - sudo bash /tmp/delete-cart.component.sh + when: destroy cart.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: cart.component metadata: @@ -2943,12 +5086,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/checkout.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/checkout.component.yaml index 16ee976c8d..667508c44d 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/checkout.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/checkout.component.yaml @@ -123,6 +123,190 @@ node_types: # ################################################################ + checkout.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + SHIPPING_SERVICE_ADDR: '"{{ SELF.SHIPPING_SERVICE_ADDR }}"' + PAYMENT_SERVICE_ADDR: '"{{ SELF.PAYMENT_SERVICE_ADDR }}"' + EMAIL_SERVICE_ADDR: '"{{ SELF.EMAIL_SERVICE_ADDR }}"' + CURRENCY_SERVICE_ADDR: '"{{ SELF.CURRENCY_SERVICE_ADDR }}"' + CART_SERVICE_ADDR: '"{{ SELF.CART_SERVICE_ADDR }}"' + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + checkout.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + SHIPPING_SERVICE_ADDR: '"{{ SELF.SHIPPING_SERVICE_ADDR }}"' + PAYMENT_SERVICE_ADDR: '"{{ SELF.PAYMENT_SERVICE_ADDR }}"' + EMAIL_SERVICE_ADDR: '"{{ SELF.EMAIL_SERVICE_ADDR }}"' + CURRENCY_SERVICE_ADDR: '"{{ SELF.CURRENCY_SERVICE_ADDR }}"' + CART_SERVICE_ADDR: '"{{ SELF.CART_SERVICE_ADDR }}"' + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + SHIPPING_SERVICE_ADDR: '"{{ SELF.SHIPPING_SERVICE_ADDR }}"' + PAYMENT_SERVICE_ADDR: '"{{ SELF.PAYMENT_SERVICE_ADDR }}"' + EMAIL_SERVICE_ADDR: '"{{ SELF.EMAIL_SERVICE_ADDR }}"' + CURRENCY_SERVICE_ADDR: '"{{ SELF.CURRENCY_SERVICE_ADDR }}"' + CART_SERVICE_ADDR: '"{{ SELF.CART_SERVICE_ADDR }}"' + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + checkout.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - PRODUCT_CATALOG_SERVICE_ADDR={{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }} + - SHIPPING_SERVICE_ADDR={{ SELF.SHIPPING_SERVICE_ADDR }} + - PAYMENT_SERVICE_ADDR={{ SELF.PAYMENT_SERVICE_ADDR }} + - EMAIL_SERVICE_ADDR={{ SELF.EMAIL_SERVICE_ADDR }} + - CURRENCY_SERVICE_ADDR={{ SELF.CURRENCY_SERVICE_ADDR }} + - CART_SERVICE_ADDR={{ SELF.CART_SERVICE_ADDR }} + - OPTIONAL_PAYMENT_FEATURE={{ SELF.optional_payment_feature }} + - PREMIUM_PAYMENT_FEATURE={{ SELF.premium_payment_feature }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' checkout.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: checkout.component metadata: @@ -285,7 +469,7 @@ node_types: OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -999,20 +1183,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - checkout.component~service.application#tar.archive::ansible@*->remote.machine: + checkout.component~service.application#tar.archive::ansible@*->local.machine: derived_from: checkout.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -1027,14 +1203,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -1107,21 +1279,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -1138,21 +1302,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -1167,27 +1323,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1208,21 +1366,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1239,6 +1389,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1246,31 +1400,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - checkout.component~service.application#tar.archive::terraform@*->remote.machine: + checkout.component~service.application#tar.archive::terraform@*->local.machine: derived_from: checkout.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1292,155 +1426,165 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-checkout.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-checkout.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-checkout.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-checkout.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-checkout.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-checkout.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-checkout.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-checkout.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-checkout.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" - SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" - PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" - EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" - CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" - CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" - OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" - PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-checkout.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-checkout.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-checkout.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-checkout.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-checkout.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-checkout.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-checkout.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-checkout.component.sh - sudo bash /tmp/configure-checkout.component.sh @@ -1449,7 +1593,7 @@ node_types: - sudo bash /tmp/stop-checkout.component.sh - sudo bash /tmp/delete-checkout.component.sh when: destroy - checkout.component~service.application#zip.archive::ansible@*->remote.machine: + checkout.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: checkout.component metadata: vintner_generated: 'true' @@ -1485,26 +1629,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1620,6 +1761,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1641,6 +1788,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1692,6 +1843,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1699,15 +1854,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - checkout.component~service.application#zip.archive::terraform@*->remote.machine: + checkout.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: checkout.component metadata: vintner_generated: 'true' @@ -1754,9 +1905,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-checkout.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1792,12 +1943,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-checkout.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-checkout.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-checkout.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-checkout.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1902,27 +2053,20 @@ node_types: - sudo bash /tmp/stop-checkout.component.sh - sudo bash /tmp/delete-checkout.component.sh when: destroy - checkout.component~service.application#zip.archive::ansible@gcp.appengine: + checkout.component~service.application#zip.archive::ansible@*->local.machine: derived_from: checkout.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1933,23 +2077,908 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + checkout.component~service.application#zip.archive::terraform@*->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-checkout.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-checkout.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-checkout.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-checkout.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-checkout.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-checkout.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-checkout.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-checkout.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-checkout.component.sh + - sudo bash /tmp/configure-checkout.component.sh + - sudo bash /tmp/start-checkout.component.sh + - inline: + - sudo bash /tmp/stop-checkout.component.sh + - sudo bash /tmp/delete-checkout.component.sh + when: destroy + checkout.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + checkout.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-checkout.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-checkout.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-checkout.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-checkout.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-checkout.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-checkout.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-checkout.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-checkout.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-checkout.component.sh + - sudo bash /tmp/configure-checkout.component.sh + - sudo bash /tmp/start-checkout.component.sh + - inline: + - sudo bash /tmp/stop-checkout.component.sh + - sudo bash /tmp/delete-checkout.component.sh + when: destroy + checkout.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ directory.path }}' @@ -2104,6 +3133,381 @@ node_types: - bucket: ${google_storage_bucket.bucket.name} name: object.zip source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + checkout.component~software.application#apt.package::ansible@*->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + checkout.component~software.application#apt.package::terraform@*->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-checkout.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-checkout.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-checkout.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-checkout.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-checkout.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-checkout.component.sh + - sudo bash /tmp/configure-checkout.component.sh + - sudo bash /tmp/start-checkout.component.sh + - inline: + - sudo bash /tmp/stop-checkout.component.sh + - sudo bash /tmp/delete-checkout.component.sh + when: destroy checkout.component~software.application#apt.package::ansible@*->remote.machine: derived_from: checkout.component metadata: @@ -2236,6 +3640,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2267,6 +3675,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2326,7 +3738,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - checkout.component~software.application#apt.archive::terraform@*->remote.machine: + checkout.component~software.application#apt.package::terraform@*->remote.machine: derived_from: checkout.component metadata: vintner_generated: 'true' @@ -2420,14 +3832,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-checkout.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2532,6 +3936,387 @@ node_types: - sudo bash /tmp/stop-checkout.component.sh - sudo bash /tmp/delete-checkout.component.sh when: destroy + checkout.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + checkout.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-checkout.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-checkout.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-checkout.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-checkout.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-checkout.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-checkout.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-checkout.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-checkout.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-checkout.component.sh + - sudo bash /tmp/configure-checkout.component.sh + - sudo bash /tmp/start-checkout.component.sh + - inline: + - sudo bash /tmp/stop-checkout.component.sh + - sudo bash /tmp/delete-checkout.component.sh + when: destroy checkout.component~software.application#tar.archive::ansible@*->remote.machine: derived_from: checkout.component metadata: @@ -2951,6 +4736,377 @@ node_types: - sudo bash /tmp/stop-checkout.component.sh - sudo bash /tmp/delete-checkout.component.sh when: destroy + checkout.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + checkout.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: checkout.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-checkout.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + PAYMENT_SERVICE_ADDR="{{ SELF.PAYMENT_SERVICE_ADDR }}" + EMAIL_SERVICE_ADDR="{{ SELF.EMAIL_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-checkout.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-checkout.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-checkout.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-checkout.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-checkout.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-checkout.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-checkout.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-checkout.component.sh + - sudo bash /tmp/configure-checkout.component.sh + - sudo bash /tmp/start-checkout.component.sh + - inline: + - sudo bash /tmp/stop-checkout.component.sh + - sudo bash /tmp/delete-checkout.component.sh + when: destroy checkout.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: checkout.component metadata: @@ -3001,12 +5157,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/currency.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/currency.component.yaml index 5df6b2ff11..e0a900826a 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/currency.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/currency.component.yaml @@ -60,6 +60,158 @@ node_types: # ################################################################ + currency.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + currency.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + currency.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' currency.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: currency.component metadata: @@ -198,7 +350,7 @@ node_types: environment: PORT: '"{{ SELF.application_port }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -808,20 +960,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - currency.component~service.application#tar.archive::ansible@*->remote.machine: + currency.component~service.application#tar.archive::ansible@*->local.machine: derived_from: currency.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -836,14 +980,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -908,21 +1048,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -939,21 +1071,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -968,27 +1092,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1009,21 +1135,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1040,6 +1158,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1047,31 +1169,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - currency.component~service.application#tar.archive::terraform@*->remote.machine: + currency.component~service.application#tar.archive::terraform@*->local.machine: derived_from: currency.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1093,147 +1195,157 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-currency.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-currency.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-currency.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-currency.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-currency.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-currency.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-currency.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-currency.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-currency.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-currency.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-currency.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-currency.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-currency.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-currency.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-currency.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-currency.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-currency.component.sh - sudo bash /tmp/configure-currency.component.sh @@ -1242,7 +1354,7 @@ node_types: - sudo bash /tmp/stop-currency.component.sh - sudo bash /tmp/delete-currency.component.sh when: destroy - currency.component~service.application#zip.archive::ansible@*->remote.machine: + currency.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: currency.component metadata: vintner_generated: 'true' @@ -1278,26 +1390,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1405,6 +1514,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1426,6 +1541,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1477,6 +1596,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1484,15 +1607,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - currency.component~service.application#zip.archive::terraform@*->remote.machine: + currency.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: currency.component metadata: vintner_generated: 'true' @@ -1539,9 +1658,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-currency.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1569,12 +1688,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-currency.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-currency.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-currency.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-currency.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1679,27 +1798,20 @@ node_types: - sudo bash /tmp/stop-currency.component.sh - sudo bash /tmp/delete-currency.component.sh when: destroy - currency.component~service.application#zip.archive::ansible@gcp.appengine: + currency.component~service.application#zip.archive::ansible@*->local.machine: derived_from: currency.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1710,94 +1822,1209 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet - args: - executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' - args: - executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + currency.component~service.application#zip.archive::terraform@*->local.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-currency.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-currency.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-currency.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-currency.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-currency.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-currency.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-currency.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-currency.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-currency.component.sh + - sudo bash /tmp/configure-currency.component.sh + - sudo bash /tmp/start-currency.component.sh + - inline: + - sudo bash /tmp/stop-currency.component.sh + - sudo bash /tmp/delete-currency.component.sh + when: destroy + currency.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + currency.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-currency.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-currency.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-currency.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-currency.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-currency.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-currency.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-currency.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-currency.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-currency.component.sh + - sudo bash /tmp/configure-currency.component.sh + - sudo bash /tmp/start-currency.component.sh + - inline: + - sudo bash /tmp/stop-currency.component.sh + - sudo bash /tmp/delete-currency.component.sh + when: destroy + currency.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: application_address: '{{ outputs.application_address | trim }}' application_endpoint: '{{ outputs.application_endpoint | trim }}' outputs: application_address: application_endpoint: - delete: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + currency.component~service.application#zip.archive::terraform@gcp.appengine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' + resource: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + currency.component~software.application#apt.package::ansible@*->local.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - args: executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - currency.component~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + currency.component~software.application#apt.package::terraform@*->local.machine: derived_from: currency.component metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1808,63 +3035,168 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-currency.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-currency.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-currency.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-currency.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-currency.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-currency.component.sh + - sudo bash /tmp/configure-currency.component.sh + - sudo bash /tmp/start-currency.component.sh + - inline: + - sudo bash /tmp/stop-currency.component.sh + - sudo bash /tmp/delete-currency.component.sh + when: destroy currency.component~software.application#apt.package::ansible@*->remote.machine: derived_from: currency.component metadata: @@ -1997,6 +3329,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2028,6 +3364,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2087,7 +3427,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - currency.component~software.application#apt.archive::terraform@*->remote.machine: + currency.component~software.application#apt.package::terraform@*->remote.machine: derived_from: currency.component metadata: vintner_generated: 'true' @@ -2173,14 +3513,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-currency.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2273,10 +3605,375 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-currency.component.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-currency.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-currency.component.sh + - sudo bash /tmp/configure-currency.component.sh + - sudo bash /tmp/start-currency.component.sh + - inline: + - sudo bash /tmp/stop-currency.component.sh + - sudo bash /tmp/delete-currency.component.sh + when: destroy + currency.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + currency.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-currency.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-currency.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-currency.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-currency.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-currency.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-currency.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-currency.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-currency.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - sudo bash /tmp/create-currency.component.sh - sudo bash /tmp/configure-currency.component.sh @@ -2688,6 +4385,361 @@ node_types: - sudo bash /tmp/stop-currency.component.sh - sudo bash /tmp/delete-currency.component.sh when: destroy + currency.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + currency.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: currency.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-currency.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-currency.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-currency.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-currency.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-currency.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-currency.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-currency.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-currency.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-currency.component.sh + - sudo bash /tmp/configure-currency.component.sh + - sudo bash /tmp/start-currency.component.sh + - inline: + - sudo bash /tmp/stop-currency.component.sh + - sudo bash /tmp/delete-currency.component.sh + when: destroy currency.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: currency.component metadata: @@ -2738,12 +4790,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/email.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/email.component.yaml index 1abda600d8..95063bdd35 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/email.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/email.component.yaml @@ -60,6 +60,158 @@ node_types: # ################################################################ + email.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + email.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + email.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' email.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: email.component metadata: @@ -198,7 +350,7 @@ node_types: environment: PORT: '"{{ SELF.application_port }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -808,20 +960,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - email.component~service.application#tar.archive::ansible@*->remote.machine: + email.component~service.application#tar.archive::ansible@*->local.machine: derived_from: email.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -836,14 +980,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -908,21 +1048,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -939,21 +1071,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -968,27 +1092,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1009,21 +1135,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1040,6 +1158,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1047,31 +1169,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - email.component~service.application#tar.archive::terraform@*->remote.machine: + email.component~service.application#tar.archive::terraform@*->local.machine: derived_from: email.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1093,147 +1195,157 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-email.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-email.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-email.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-email.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-email.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-email.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-email.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-email.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-email.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-email.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-email.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-email.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-email.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-email.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-email.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-email.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-email.component.sh - sudo bash /tmp/configure-email.component.sh @@ -1242,7 +1354,7 @@ node_types: - sudo bash /tmp/stop-email.component.sh - sudo bash /tmp/delete-email.component.sh when: destroy - email.component~service.application#zip.archive::ansible@*->remote.machine: + email.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: email.component metadata: vintner_generated: 'true' @@ -1278,26 +1390,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1405,6 +1514,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1426,6 +1541,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1477,6 +1596,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1484,15 +1607,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - email.component~service.application#zip.archive::terraform@*->remote.machine: + email.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: email.component metadata: vintner_generated: 'true' @@ -1539,9 +1658,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-email.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1569,12 +1688,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-email.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-email.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-email.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-email.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1679,27 +1798,20 @@ node_types: - sudo bash /tmp/stop-email.component.sh - sudo bash /tmp/delete-email.component.sh when: destroy - email.component~service.application#zip.archive::ansible@gcp.appengine: + email.component~service.application#zip.archive::ansible@*->local.machine: derived_from: email.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1710,94 +1822,1209 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet - args: - executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' - args: - executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + email.component~service.application#zip.archive::terraform@*->local.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-email.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-email.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-email.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-email.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-email.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-email.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-email.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-email.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-email.component.sh + - sudo bash /tmp/configure-email.component.sh + - sudo bash /tmp/start-email.component.sh + - inline: + - sudo bash /tmp/stop-email.component.sh + - sudo bash /tmp/delete-email.component.sh + when: destroy + email.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + email.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-email.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-email.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-email.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-email.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-email.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-email.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-email.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-email.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-email.component.sh + - sudo bash /tmp/configure-email.component.sh + - sudo bash /tmp/start-email.component.sh + - inline: + - sudo bash /tmp/stop-email.component.sh + - sudo bash /tmp/delete-email.component.sh + when: destroy + email.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: email.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: application_address: '{{ outputs.application_address | trim }}' application_endpoint: '{{ outputs.application_endpoint | trim }}' outputs: application_address: application_endpoint: - delete: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + email.component~service.application#zip.archive::terraform@gcp.appengine: + derived_from: email.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' + resource: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + email.component~software.application#apt.package::ansible@*->local.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - args: executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - email.component~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + email.component~software.application#apt.package::terraform@*->local.machine: derived_from: email.component metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1808,63 +3035,168 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-email.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-email.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-email.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-email.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-email.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-email.component.sh + - sudo bash /tmp/configure-email.component.sh + - sudo bash /tmp/start-email.component.sh + - inline: + - sudo bash /tmp/stop-email.component.sh + - sudo bash /tmp/delete-email.component.sh + when: destroy email.component~software.application#apt.package::ansible@*->remote.machine: derived_from: email.component metadata: @@ -1997,6 +3329,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2028,6 +3364,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2087,7 +3427,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - email.component~software.application#apt.archive::terraform@*->remote.machine: + email.component~software.application#apt.package::terraform@*->remote.machine: derived_from: email.component metadata: vintner_generated: 'true' @@ -2173,14 +3513,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-email.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2273,10 +3605,375 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-email.component.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-email.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-email.component.sh + - sudo bash /tmp/configure-email.component.sh + - sudo bash /tmp/start-email.component.sh + - inline: + - sudo bash /tmp/stop-email.component.sh + - sudo bash /tmp/delete-email.component.sh + when: destroy + email.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + email.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-email.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-email.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-email.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-email.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-email.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-email.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-email.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-email.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - sudo bash /tmp/create-email.component.sh - sudo bash /tmp/configure-email.component.sh @@ -2688,6 +4385,361 @@ node_types: - sudo bash /tmp/stop-email.component.sh - sudo bash /tmp/delete-email.component.sh when: destroy + email.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + email.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: email.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-email.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-email.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-email.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-email.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-email.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-email.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-email.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-email.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-email.component.sh + - sudo bash /tmp/configure-email.component.sh + - sudo bash /tmp/start-email.component.sh + - inline: + - sudo bash /tmp/stop-email.component.sh + - sudo bash /tmp/delete-email.component.sh + when: destroy email.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: email.component metadata: @@ -2738,12 +4790,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/frontend.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/frontend.component.yaml index cb1f3f6530..7f69cdf4ad 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/frontend.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/frontend.component.yaml @@ -139,6 +139,202 @@ node_types: # ################################################################ + frontend.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + ENV_PLATFORM: '"{{ SELF.ENV_PLATFORM }}"' + CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' + CURRENCY_SERVICE_ADDR: '"{{ SELF.CURRENCY_SERVICE_ADDR }}"' + SHIPPING_SERVICE_ADDR: '"{{ SELF.SHIPPING_SERVICE_ADDR }}"' + CART_SERVICE_ADDR: '"{{ SELF.CART_SERVICE_ADDR }}"' + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' + AD_SERVICE_ADDR: '"{{ SELF.AD_SERVICE_ADDR }}"' + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + SHOPPING_ASSISTANT_SERVICE_ADDR: '"{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + frontend.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + ENV_PLATFORM: '"{{ SELF.ENV_PLATFORM }}"' + CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' + CURRENCY_SERVICE_ADDR: '"{{ SELF.CURRENCY_SERVICE_ADDR }}"' + SHIPPING_SERVICE_ADDR: '"{{ SELF.SHIPPING_SERVICE_ADDR }}"' + CART_SERVICE_ADDR: '"{{ SELF.CART_SERVICE_ADDR }}"' + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' + AD_SERVICE_ADDR: '"{{ SELF.AD_SERVICE_ADDR }}"' + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + SHOPPING_ASSISTANT_SERVICE_ADDR: '"{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + ENV_PLATFORM: '"{{ SELF.ENV_PLATFORM }}"' + CHECKOUT_SERVICE_ADDR: '"{{ SELF.CHECKOUT_SERVICE_ADDR }}"' + CURRENCY_SERVICE_ADDR: '"{{ SELF.CURRENCY_SERVICE_ADDR }}"' + SHIPPING_SERVICE_ADDR: '"{{ SELF.SHIPPING_SERVICE_ADDR }}"' + CART_SERVICE_ADDR: '"{{ SELF.CART_SERVICE_ADDR }}"' + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + RECOMMENDATION_SERVICE_ADDR: '"{{ SELF.RECOMMENDATION_SERVICE_ADDR }}"' + AD_SERVICE_ADDR: '"{{ SELF.AD_SERVICE_ADDR }}"' + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + SHOPPING_ASSISTANT_SERVICE_ADDR: '"{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + frontend.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - ENV_PLATFORM={{ SELF.ENV_PLATFORM }} + - CHECKOUT_SERVICE_ADDR={{ SELF.CHECKOUT_SERVICE_ADDR }} + - CURRENCY_SERVICE_ADDR={{ SELF.CURRENCY_SERVICE_ADDR }} + - SHIPPING_SERVICE_ADDR={{ SELF.SHIPPING_SERVICE_ADDR }} + - CART_SERVICE_ADDR={{ SELF.CART_SERVICE_ADDR }} + - PRODUCT_CATALOG_SERVICE_ADDR={{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }} + - RECOMMENDATION_SERVICE_ADDR={{ SELF.RECOMMENDATION_SERVICE_ADDR }} + - AD_SERVICE_ADDR={{ SELF.AD_SERVICE_ADDR }} + - OPTIONAL_PAYMENT_FEATURE={{ SELF.optional_payment_feature }} + - PREMIUM_PAYMENT_FEATURE={{ SELF.premium_payment_feature }} + - SHOPPING_ASSISTANT_SERVICE_ADDR={{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' frontend.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: frontend.component metadata: @@ -310,7 +506,7 @@ node_types: PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' SHOPPING_ASSISTANT_SERVICE_ADDR: '"{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -1063,20 +1259,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - frontend.component~service.application#tar.archive::ansible@*->remote.machine: + frontend.component~service.application#tar.archive::ansible@*->local.machine: derived_from: frontend.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -1091,14 +1279,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -1174,21 +1358,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -1205,21 +1381,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -1234,27 +1402,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1275,21 +1445,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1306,6 +1468,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1313,31 +1479,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - frontend.component~service.application#tar.archive::terraform@*->remote.machine: + frontend.component~service.application#tar.archive::terraform@*->local.machine: derived_from: frontend.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1359,158 +1505,168 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-frontend.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-frontend.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-frontend.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-frontend.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-frontend.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-frontend.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-frontend.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-frontend.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-frontend.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" - CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" - CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" - SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" - CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" - PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" - RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" - AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" - OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" - PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" - SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-frontend.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-frontend.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-frontend.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-frontend.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-frontend.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-frontend.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-frontend.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-frontend.component.sh - sudo bash /tmp/configure-frontend.component.sh @@ -1519,7 +1675,7 @@ node_types: - sudo bash /tmp/stop-frontend.component.sh - sudo bash /tmp/delete-frontend.component.sh when: destroy - frontend.component~service.application#zip.archive::ansible@*->remote.machine: + frontend.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: frontend.component metadata: vintner_generated: 'true' @@ -1555,26 +1711,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1693,6 +1846,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1714,6 +1873,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1765,6 +1928,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1772,15 +1939,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - frontend.component~service.application#zip.archive::terraform@*->remote.machine: + frontend.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: frontend.component metadata: vintner_generated: 'true' @@ -1827,9 +1990,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-frontend.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1868,12 +2031,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-frontend.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-frontend.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-frontend.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-frontend.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1978,27 +2141,20 @@ node_types: - sudo bash /tmp/stop-frontend.component.sh - sudo bash /tmp/delete-frontend.component.sh when: destroy - frontend.component~service.application#zip.archive::ansible@gcp.appengine: + frontend.component~service.application#zip.archive::ansible@*->local.machine: derived_from: frontend.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: https - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -2009,15 +2165,912 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + frontend.component~service.application#zip.archive::terraform@*->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-frontend.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-frontend.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-frontend.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-frontend.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-frontend.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-frontend.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-frontend.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-frontend.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-frontend.component.sh + - sudo bash /tmp/configure-frontend.component.sh + - sudo bash /tmp/start-frontend.component.sh + - inline: + - sudo bash /tmp/stop-frontend.component.sh + - sudo bash /tmp/delete-frontend.component.sh + when: destroy + frontend.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + frontend.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-frontend.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-frontend.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-frontend.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-frontend.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-frontend.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-frontend.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-frontend.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-frontend.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-frontend.component.sh + - sudo bash /tmp/configure-frontend.component.sh + - sudo bash /tmp/start-frontend.component.sh + - inline: + - sudo bash /tmp/stop-frontend.component.sh + - sudo bash /tmp/delete-frontend.component.sh + when: destroy + frontend.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: https + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command failed_when: - "'Created' not in app_create_command.stderr" - "'already contains' not in app_create_command.stderr" @@ -2186,6 +3239,384 @@ node_types: - bucket: ${google_storage_bucket.bucket.name} name: object.zip source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + frontend.component~software.application#apt.package::ansible@*->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + frontend.component~software.application#apt.package::terraform@*->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-frontend.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-frontend.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-frontend.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-frontend.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-frontend.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-frontend.component.sh + - sudo bash /tmp/configure-frontend.component.sh + - sudo bash /tmp/start-frontend.component.sh + - inline: + - sudo bash /tmp/stop-frontend.component.sh + - sudo bash /tmp/delete-frontend.component.sh + when: destroy frontend.component~software.application#apt.package::ansible@*->remote.machine: derived_from: frontend.component metadata: @@ -2318,6 +3749,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2349,6 +3784,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2408,7 +3847,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - frontend.component~software.application#apt.archive::terraform@*->remote.machine: + frontend.component~software.application#apt.package::terraform@*->remote.machine: derived_from: frontend.component metadata: vintner_generated: 'true' @@ -2505,14 +3944,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-frontend.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2617,6 +4048,393 @@ node_types: - sudo bash /tmp/stop-frontend.component.sh - sudo bash /tmp/delete-frontend.component.sh when: destroy + frontend.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + frontend.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-frontend.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-frontend.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-frontend.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-frontend.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-frontend.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-frontend.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-frontend.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-frontend.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-frontend.component.sh + - sudo bash /tmp/configure-frontend.component.sh + - sudo bash /tmp/start-frontend.component.sh + - inline: + - sudo bash /tmp/stop-frontend.component.sh + - sudo bash /tmp/delete-frontend.component.sh + when: destroy frontend.component~software.application#tar.archive::ansible@*->remote.machine: derived_from: frontend.component metadata: @@ -3042,6 +4860,383 @@ node_types: - sudo bash /tmp/stop-frontend.component.sh - sudo bash /tmp/delete-frontend.component.sh when: destroy + frontend.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + frontend.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: frontend.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-frontend.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + ENV_PLATFORM="{{ SELF.ENV_PLATFORM }}" + CHECKOUT_SERVICE_ADDR="{{ SELF.CHECKOUT_SERVICE_ADDR }}" + CURRENCY_SERVICE_ADDR="{{ SELF.CURRENCY_SERVICE_ADDR }}" + SHIPPING_SERVICE_ADDR="{{ SELF.SHIPPING_SERVICE_ADDR }}" + CART_SERVICE_ADDR="{{ SELF.CART_SERVICE_ADDR }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + RECOMMENDATION_SERVICE_ADDR="{{ SELF.RECOMMENDATION_SERVICE_ADDR }}" + AD_SERVICE_ADDR="{{ SELF.AD_SERVICE_ADDR }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + SHOPPING_ASSISTANT_SERVICE_ADDR="{{ SELF.SHOPPING_ASSISTANT_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-frontend.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-frontend.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-frontend.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-frontend.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-frontend.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-frontend.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-frontend.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-frontend.component.sh + - sudo bash /tmp/configure-frontend.component.sh + - sudo bash /tmp/start-frontend.component.sh + - inline: + - sudo bash /tmp/stop-frontend.component.sh + - sudo bash /tmp/delete-frontend.component.sh + when: destroy frontend.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: frontend.component metadata: @@ -3092,12 +5287,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/payment.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/payment.component.yaml index c2b7e2ce29..58a629fa78 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/payment.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/payment.component.yaml @@ -66,6 +66,166 @@ node_types: # ################################################################ + payment.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + payment.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + payment.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - OPTIONAL_PAYMENT_FEATURE={{ SELF.optional_payment_feature }} + - PREMIUM_PAYMENT_FEATURE={{ SELF.premium_payment_feature }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' payment.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: payment.component metadata: @@ -210,7 +370,7 @@ node_types: OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -846,20 +1006,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - payment.component~service.application#tar.archive::ansible@*->remote.machine: + payment.component~service.application#tar.archive::ansible@*->local.machine: derived_from: payment.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -874,14 +1026,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -948,21 +1096,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -979,21 +1119,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -1008,27 +1140,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1049,21 +1183,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1080,6 +1206,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1087,31 +1217,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - payment.component~service.application#tar.archive::terraform@*->remote.machine: + payment.component~service.application#tar.archive::terraform@*->local.machine: derived_from: payment.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1133,149 +1243,159 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-payment.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-payment.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-payment.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-payment.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-payment.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-payment.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-payment.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-payment.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-payment.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" - PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-payment.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-payment.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-payment.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-payment.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-payment.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-payment.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-payment.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-payment.component.sh - sudo bash /tmp/configure-payment.component.sh @@ -1284,7 +1404,7 @@ node_types: - sudo bash /tmp/stop-payment.component.sh - sudo bash /tmp/delete-payment.component.sh when: destroy - payment.component~service.application#zip.archive::ansible@*->remote.machine: + payment.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: payment.component metadata: vintner_generated: 'true' @@ -1320,26 +1440,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1449,6 +1566,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1470,6 +1593,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1521,6 +1648,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1528,15 +1659,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - payment.component~service.application#zip.archive::terraform@*->remote.machine: + payment.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: payment.component metadata: vintner_generated: 'true' @@ -1583,9 +1710,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-payment.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1615,12 +1742,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-payment.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-payment.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-payment.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-payment.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1725,27 +1852,20 @@ node_types: - sudo bash /tmp/stop-payment.component.sh - sudo bash /tmp/delete-payment.component.sh when: destroy - payment.component~service.application#zip.archive::ansible@gcp.appengine: + payment.component~service.application#zip.archive::ansible@*->local.machine: derived_from: payment.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1756,96 +1876,1221 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: - OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' - PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet - args: - executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: - application_address: '{{ outputs.application_address | trim }}' - application_endpoint: '{{ outputs.application_endpoint | trim }}' - outputs: - application_address: - application_endpoint: - delete: + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - payment.component~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + payment.component~service.application#zip.archive::terraform@*->local.machine: derived_from: payment.component metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-payment.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-payment.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-payment.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-payment.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-payment.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-payment.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-payment.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-payment.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-payment.component.sh + - sudo bash /tmp/configure-payment.component.sh + - sudo bash /tmp/start-payment.component.sh + - inline: + - sudo bash /tmp/stop-payment.component.sh + - sudo bash /tmp/delete-payment.component.sh + when: destroy + payment.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + payment.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-payment.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-payment.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-payment.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-payment.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-payment.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-payment.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-payment.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-payment.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-payment.component.sh + - sudo bash /tmp/configure-payment.component.sh + - sudo bash /tmp/start-payment.component.sh + - inline: + - sudo bash /tmp/stop-payment.component.sh + - sudo bash /tmp/delete-payment.component.sh + when: destroy + payment.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address | trim }}' + application_endpoint: '{{ outputs.application_endpoint | trim }}' + outputs: + application_address: + application_endpoint: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + payment.component~service.application#zip.archive::terraform@gcp.appengine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' + resource: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' + PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + payment.component~software.application#apt.package::ansible@*->local.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + payment.component~software.application#apt.package::terraform@*->local.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1856,65 +3101,170 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - OPTIONAL_PAYMENT_FEATURE: '"{{ SELF.optional_payment_feature }}"' - PREMIUM_PAYMENT_FEATURE: '"{{ SELF.premium_payment_feature }}"' - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-payment.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-payment.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-payment.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-payment.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-payment.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-payment.component.sh + - sudo bash /tmp/configure-payment.component.sh + - sudo bash /tmp/start-payment.component.sh + - inline: + - sudo bash /tmp/stop-payment.component.sh + - sudo bash /tmp/delete-payment.component.sh + when: destroy payment.component~software.application#apt.package::ansible@*->remote.machine: derived_from: payment.component metadata: @@ -2047,6 +3397,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2078,6 +3432,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2137,7 +3495,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - payment.component~software.application#apt.archive::terraform@*->remote.machine: + payment.component~software.application#apt.package::terraform@*->remote.machine: derived_from: payment.component metadata: vintner_generated: 'true' @@ -2225,14 +3583,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-payment.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2337,6 +3687,375 @@ node_types: - sudo bash /tmp/stop-payment.component.sh - sudo bash /tmp/delete-payment.component.sh when: destroy + payment.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + payment.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-payment.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-payment.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-payment.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-payment.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-payment.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-payment.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-payment.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-payment.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-payment.component.sh + - sudo bash /tmp/configure-payment.component.sh + - sudo bash /tmp/start-payment.component.sh + - inline: + - sudo bash /tmp/stop-payment.component.sh + - sudo bash /tmp/delete-payment.component.sh + when: destroy payment.component~software.application#tar.archive::ansible@*->remote.machine: derived_from: payment.component metadata: @@ -2744,6 +4463,365 @@ node_types: - sudo bash /tmp/stop-payment.component.sh - sudo bash /tmp/delete-payment.component.sh when: destroy + payment.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + payment.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: payment.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-payment.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + OPTIONAL_PAYMENT_FEATURE="{{ SELF.optional_payment_feature }}" + PREMIUM_PAYMENT_FEATURE="{{ SELF.premium_payment_feature }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-payment.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-payment.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-payment.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-payment.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-payment.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-payment.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-payment.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-payment.component.sh + - sudo bash /tmp/configure-payment.component.sh + - sudo bash /tmp/start-payment.component.sh + - inline: + - sudo bash /tmp/stop-payment.component.sh + - sudo bash /tmp/delete-payment.component.sh + when: destroy payment.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: payment.component metadata: @@ -2794,12 +4872,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/product.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/product.component.yaml index 87c5a4d15c..706f527f26 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/product.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/product.component.yaml @@ -66,6 +66,158 @@ node_types: # ################################################################ + product.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + product.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + product.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' product.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: product.component metadata: @@ -204,7 +356,7 @@ node_types: environment: PORT: '"{{ SELF.application_port }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -814,20 +966,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - product.component~service.application#tar.archive::ansible@*->remote.machine: + product.component~service.application#tar.archive::ansible@*->local.machine: derived_from: product.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -842,14 +986,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -914,21 +1054,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -945,21 +1077,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -974,27 +1098,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1015,21 +1141,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1046,6 +1164,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1053,31 +1175,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - product.component~service.application#tar.archive::terraform@*->remote.machine: + product.component~service.application#tar.archive::terraform@*->local.machine: derived_from: product.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1099,147 +1201,157 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-product.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-product.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-product.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-product.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-product.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-product.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-product.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-product.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-product.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-product.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-product.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-product.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-product.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-product.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-product.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-product.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-product.component.sh - sudo bash /tmp/configure-product.component.sh @@ -1248,7 +1360,7 @@ node_types: - sudo bash /tmp/stop-product.component.sh - sudo bash /tmp/delete-product.component.sh when: destroy - product.component~service.application#zip.archive::ansible@*->remote.machine: + product.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: product.component metadata: vintner_generated: 'true' @@ -1284,26 +1396,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1411,6 +1520,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1432,6 +1547,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1483,6 +1602,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1490,15 +1613,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - product.component~service.application#zip.archive::terraform@*->remote.machine: + product.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: product.component metadata: vintner_generated: 'true' @@ -1545,9 +1664,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-product.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1575,12 +1694,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-product.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-product.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-product.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-product.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1685,27 +1804,20 @@ node_types: - sudo bash /tmp/stop-product.component.sh - sudo bash /tmp/delete-product.component.sh when: destroy - product.component~service.application#zip.archive::ansible@gcp.appengine: + product.component~service.application#zip.archive::ansible@*->local.machine: derived_from: product.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1716,94 +1828,1209 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet - args: - executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' - args: - executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + product.component~service.application#zip.archive::terraform@*->local.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-product.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-product.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-product.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-product.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-product.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-product.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-product.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-product.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-product.component.sh + - sudo bash /tmp/configure-product.component.sh + - sudo bash /tmp/start-product.component.sh + - inline: + - sudo bash /tmp/stop-product.component.sh + - sudo bash /tmp/delete-product.component.sh + when: destroy + product.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + product.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-product.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-product.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-product.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-product.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-product.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-product.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-product.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-product.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-product.component.sh + - sudo bash /tmp/configure-product.component.sh + - sudo bash /tmp/start-product.component.sh + - inline: + - sudo bash /tmp/stop-product.component.sh + - sudo bash /tmp/delete-product.component.sh + when: destroy + product.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: product.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: application_address: '{{ outputs.application_address | trim }}' application_endpoint: '{{ outputs.application_endpoint | trim }}' outputs: application_address: application_endpoint: - delete: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + product.component~service.application#zip.archive::terraform@gcp.appengine: + derived_from: product.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' + resource: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + product.component~software.application#apt.package::ansible@*->local.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - args: executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - product.component~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + product.component~software.application#apt.package::terraform@*->local.machine: derived_from: product.component metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1814,63 +3041,168 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-product.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-product.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-product.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-product.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-product.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-product.component.sh + - sudo bash /tmp/configure-product.component.sh + - sudo bash /tmp/start-product.component.sh + - inline: + - sudo bash /tmp/stop-product.component.sh + - sudo bash /tmp/delete-product.component.sh + when: destroy product.component~software.application#apt.package::ansible@*->remote.machine: derived_from: product.component metadata: @@ -2003,6 +3335,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2034,6 +3370,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2093,7 +3433,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - product.component~software.application#apt.archive::terraform@*->remote.machine: + product.component~software.application#apt.package::terraform@*->remote.machine: derived_from: product.component metadata: vintner_generated: 'true' @@ -2179,14 +3519,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-product.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2279,10 +3611,375 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-product.component.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-product.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-product.component.sh + - sudo bash /tmp/configure-product.component.sh + - sudo bash /tmp/start-product.component.sh + - inline: + - sudo bash /tmp/stop-product.component.sh + - sudo bash /tmp/delete-product.component.sh + when: destroy + product.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + product.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-product.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-product.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-product.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-product.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-product.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-product.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-product.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-product.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - sudo bash /tmp/create-product.component.sh - sudo bash /tmp/configure-product.component.sh @@ -2694,6 +4391,361 @@ node_types: - sudo bash /tmp/stop-product.component.sh - sudo bash /tmp/delete-product.component.sh when: destroy + product.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + product.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: product.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-product.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-product.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-product.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-product.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-product.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-product.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-product.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-product.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-product.component.sh + - sudo bash /tmp/configure-product.component.sh + - sudo bash /tmp/start-product.component.sh + - inline: + - sudo bash /tmp/stop-product.component.sh + - sudo bash /tmp/delete-product.component.sh + when: destroy product.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: product.component metadata: @@ -2744,12 +4796,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/recommendation.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/recommendation.component.yaml index 20e4537748..35ec74b665 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/recommendation.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/recommendation.component.yaml @@ -76,6 +76,162 @@ node_types: # ################################################################ + recommendation.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + recommendation.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + recommendation.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - PRODUCT_CATALOG_SERVICE_ADDR={{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' recommendation.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: recommendation.component metadata: @@ -217,7 +373,7 @@ node_types: PORT: '"{{ SELF.application_port }}"' PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -840,20 +996,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - recommendation.component~service.application#tar.archive::ansible@*->remote.machine: + recommendation.component~service.application#tar.archive::ansible@*->local.machine: derived_from: recommendation.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -868,14 +1016,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -941,21 +1085,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -972,21 +1108,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -1001,27 +1129,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1042,21 +1172,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1073,6 +1195,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1080,31 +1206,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - recommendation.component~service.application#tar.archive::terraform@*->remote.machine: + recommendation.component~service.application#tar.archive::terraform@*->local.machine: derived_from: recommendation.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1126,148 +1232,158 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-recommendation.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-recommendation.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-recommendation.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-recommendation.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-recommendation.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-recommendation.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-recommendation.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-recommendation.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-recommendation.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-recommendation.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-recommendation.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-recommendation.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-recommendation.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-recommendation.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-recommendation.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-recommendation.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-recommendation.component.sh - sudo bash /tmp/configure-recommendation.component.sh @@ -1276,7 +1392,7 @@ node_types: - sudo bash /tmp/stop-recommendation.component.sh - sudo bash /tmp/delete-recommendation.component.sh when: destroy - recommendation.component~service.application#zip.archive::ansible@*->remote.machine: + recommendation.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: recommendation.component metadata: vintner_generated: 'true' @@ -1312,26 +1428,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1440,6 +1553,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1461,6 +1580,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1512,6 +1635,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1519,15 +1646,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - recommendation.component~service.application#zip.archive::terraform@*->remote.machine: + recommendation.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: recommendation.component metadata: vintner_generated: 'true' @@ -1574,9 +1697,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-recommendation.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1605,12 +1728,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-recommendation.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-recommendation.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-recommendation.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-recommendation.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1715,27 +1838,20 @@ node_types: - sudo bash /tmp/stop-recommendation.component.sh - sudo bash /tmp/delete-recommendation.component.sh when: destroy - recommendation.component~service.application#zip.archive::ansible@gcp.appengine: + recommendation.component~service.application#zip.archive::ansible@*->local.machine: derived_from: recommendation.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1746,95 +1862,1215 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: - PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet - args: - executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' - args: - executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: - application_address: '{{ outputs.application_address | trim }}' - application_endpoint: '{{ outputs.application_endpoint | trim }}' - outputs: - application_address: - application_endpoint: - delete: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - recommendation.component~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + recommendation.component~service.application#zip.archive::terraform@*->local.machine: derived_from: recommendation.component metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - application_protocol: + application_directory: type: string - default: grpcs - gcp_service_account_file: + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-recommendation.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-recommendation.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-recommendation.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-recommendation.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-recommendation.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-recommendation.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-recommendation.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-recommendation.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-recommendation.component.sh + - sudo bash /tmp/configure-recommendation.component.sh + - sudo bash /tmp/start-recommendation.component.sh + - inline: + - sudo bash /tmp/stop-recommendation.component.sh + - sudo bash /tmp/delete-recommendation.component.sh + when: destroy + recommendation.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + recommendation.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-recommendation.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-recommendation.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-recommendation.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-recommendation.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-recommendation.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-recommendation.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-recommendation.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-recommendation.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-recommendation.component.sh + - sudo bash /tmp/configure-recommendation.component.sh + - sudo bash /tmp/start-recommendation.component.sh + - inline: + - sudo bash /tmp/stop-recommendation.component.sh + - sudo bash /tmp/delete-recommendation.component.sh + when: destroy + recommendation.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address | trim }}' + application_endpoint: '{{ outputs.application_endpoint | trim }}' + outputs: + application_address: + application_endpoint: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + recommendation.component~service.application#zip.archive::terraform@gcp.appengine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' + resource: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + recommendation.component~software.application#apt.package::ansible@*->local.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + recommendation.component~software.application#apt.package::terraform@*->local.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1845,64 +3081,169 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - PRODUCT_CATALOG_SERVICE_ADDR: '"{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}"' - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-recommendation.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-recommendation.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-recommendation.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-recommendation.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-recommendation.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-recommendation.component.sh + - sudo bash /tmp/configure-recommendation.component.sh + - sudo bash /tmp/start-recommendation.component.sh + - inline: + - sudo bash /tmp/stop-recommendation.component.sh + - sudo bash /tmp/delete-recommendation.component.sh + when: destroy recommendation.component~software.application#apt.package::ansible@*->remote.machine: derived_from: recommendation.component metadata: @@ -2035,6 +3376,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2066,6 +3411,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2125,7 +3474,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - recommendation.component~software.application#apt.archive::terraform@*->remote.machine: + recommendation.component~software.application#apt.package::terraform@*->remote.machine: derived_from: recommendation.component metadata: vintner_generated: 'true' @@ -2212,14 +3561,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-recommendation.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2324,6 +3665,373 @@ node_types: - sudo bash /tmp/stop-recommendation.component.sh - sudo bash /tmp/delete-recommendation.component.sh when: destroy + recommendation.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + recommendation.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-recommendation.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-recommendation.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-recommendation.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-recommendation.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-recommendation.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-recommendation.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-recommendation.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-recommendation.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-recommendation.component.sh + - sudo bash /tmp/configure-recommendation.component.sh + - sudo bash /tmp/start-recommendation.component.sh + - inline: + - sudo bash /tmp/stop-recommendation.component.sh + - sudo bash /tmp/delete-recommendation.component.sh + when: destroy recommendation.component~software.application#tar.archive::ansible@*->remote.machine: derived_from: recommendation.component metadata: @@ -2729,6 +4437,363 @@ node_types: - sudo bash /tmp/stop-recommendation.component.sh - sudo bash /tmp/delete-recommendation.component.sh when: destroy + recommendation.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + recommendation.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: recommendation.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-recommendation.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + PRODUCT_CATALOG_SERVICE_ADDR="{{ SELF.PRODUCT_CATALOG_SERVICE_ADDR }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-recommendation.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-recommendation.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-recommendation.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-recommendation.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-recommendation.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-recommendation.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-recommendation.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-recommendation.component.sh + - sudo bash /tmp/configure-recommendation.component.sh + - sudo bash /tmp/start-recommendation.component.sh + - inline: + - sudo bash /tmp/stop-recommendation.component.sh + - sudo bash /tmp/delete-recommendation.component.sh + when: destroy recommendation.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: recommendation.component metadata: @@ -2779,12 +4844,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/shipping.component.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/shipping.component.yaml index 637472cdb6..3879816495 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/shipping.component.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/boutique/shipping.component.yaml @@ -60,6 +60,158 @@ node_types: # ################################################################ + shipping.component~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + shipping.component~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + PORT: '"{{ SELF.application_port }}"' + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + shipping.component~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - PORT={{ SELF.application_port }} + - DISABLE_PROFILER={{ SELF.disable_profiler }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' shipping.component~service.application#docker.image::ansible@docker.engine->remote.machine: derived_from: shipping.component metadata: @@ -198,7 +350,7 @@ node_types: environment: PORT: '"{{ SELF.application_port }}"' DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: apply compose + - name: unapply compose ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash @@ -808,20 +960,12 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP - shipping.component~service.application#tar.archive::ansible@*->remote.machine: + shipping.component~service.application#tar.archive::ansible@*->local.machine: derived_from: shipping.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -836,14 +980,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -908,21 +1048,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -939,21 +1071,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -968,27 +1092,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1009,21 +1135,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1040,6 +1158,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1047,31 +1169,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - shipping.component~service.application#tar.archive::terraform@*->remote.machine: + shipping.component~service.application#tar.archive::terraform@*->local.machine: derived_from: shipping.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1093,147 +1195,157 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-shipping.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shipping.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-shipping.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-shipping.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shipping.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-shipping.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-shipping.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-shipping.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-shipping.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - DISABLE_PROFILER="{{ SELF.disable_profiler }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-shipping.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-shipping.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-shipping.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-shipping.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-shipping.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-shipping.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-shipping.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-shipping.component.sh - sudo bash /tmp/configure-shipping.component.sh @@ -1242,7 +1354,7 @@ node_types: - sudo bash /tmp/stop-shipping.component.sh - sudo bash /tmp/delete-shipping.component.sh when: destroy - shipping.component~service.application#zip.archive::ansible@*->remote.machine: + shipping.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: shipping.component metadata: vintner_generated: 'true' @@ -1278,26 +1390,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1405,6 +1514,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1426,6 +1541,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1477,6 +1596,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1484,15 +1607,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - shipping.component~service.application#zip.archive::terraform@*->remote.machine: + shipping.component~service.application#tar.archive::terraform@*->remote.machine: derived_from: shipping.component metadata: vintner_generated: 'true' @@ -1539,9 +1658,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-shipping.component - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | [Unit] After=network.target @@ -1569,12 +1688,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-shipping.component {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shipping.component {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-shipping.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-shipping.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1679,27 +1798,20 @@ node_types: - sudo bash /tmp/stop-shipping.component.sh - sudo bash /tmp/delete-shipping.component.sh when: destroy - shipping.component~service.application#zip.archive::ansible@gcp.appengine: + shipping.component~service.application#zip.archive::ansible@*->local.machine: derived_from: shipping.component metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1710,94 +1822,1209 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet - args: - executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in working directory + - name: extract deployment artifact in application directory ansible.builtin.unarchive: src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet - args: - executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' - args: - executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + shipping.component~service.application#zip.archive::terraform@*->local.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-shipping.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shipping.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-shipping.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-shipping.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shipping.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-shipping.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-shipping.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-shipping.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-shipping.component.sh + - sudo bash /tmp/configure-shipping.component.sh + - sudo bash /tmp/start-shipping.component.sh + - inline: + - sudo bash /tmp/stop-shipping.component.sh + - sudo bash /tmp/delete-shipping.component.sh + when: destroy + shipping.component~service.application#zip.archive::ansible@*->remote.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + shipping.component~service.application#zip.archive::terraform@*->remote.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-shipping.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shipping.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-shipping.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-shipping.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-shipping.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-shipping.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-shipping.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-shipping.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-shipping.component.sh + - sudo bash /tmp/configure-shipping.component.sh + - sudo bash /tmp/start-shipping.component.sh + - inline: + - sudo bash /tmp/stop-shipping.component.sh + - sudo bash /tmp/delete-shipping.component.sh + when: destroy + shipping.component~service.application#zip.archive::ansible@gcp.appengine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: application_address: '{{ outputs.application_address | trim }}' application_endpoint: '{{ outputs.application_endpoint | trim }}' outputs: application_address: application_endpoint: - delete: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + shipping.component~service.application#zip.archive::terraform@gcp.appengine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_protocol: + type: string + default: grpcs + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' + resource: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + shipping.component~software.application#apt.package::ansible@*->local.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - args: executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - shipping.component~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + shipping.component~software.application#apt.package::terraform@*->local.machine: derived_from: shipping.component metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - application_protocol: - type: string - default: grpcs - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -1808,63 +3035,168 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - DISABLE_PROFILER: '"{{ SELF.disable_profiler }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-shipping.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shipping.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-shipping.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-shipping.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-shipping.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-shipping.component.sh + - sudo bash /tmp/configure-shipping.component.sh + - sudo bash /tmp/start-shipping.component.sh + - inline: + - sudo bash /tmp/stop-shipping.component.sh + - sudo bash /tmp/delete-shipping.component.sh + when: destroy shipping.component~software.application#apt.package::ansible@*->remote.machine: derived_from: shipping.component metadata: @@ -1997,6 +3329,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2028,6 +3364,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2087,7 +3427,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - shipping.component~software.application#apt.archive::terraform@*->remote.machine: + shipping.component~software.application#apt.package::terraform@*->remote.machine: derived_from: shipping.component metadata: vintner_generated: 'true' @@ -2173,14 +3513,6 @@ node_types: DISABLE_PROFILER="{{ SELF.disable_profiler }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-shipping.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2273,10 +3605,375 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-shipping.component.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-shipping.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-shipping.component.sh + - sudo bash /tmp/configure-shipping.component.sh + - sudo bash /tmp/start-shipping.component.sh + - inline: + - sudo bash /tmp/stop-shipping.component.sh + - sudo bash /tmp/delete-shipping.component.sh + when: destroy + shipping.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + shipping.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-shipping.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shipping.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-shipping.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-shipping.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shipping.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-shipping.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-shipping.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-shipping.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - sudo bash /tmp/create-shipping.component.sh - sudo bash /tmp/configure-shipping.component.sh @@ -2688,6 +4385,361 @@ node_types: - sudo bash /tmp/stop-shipping.component.sh - sudo bash /tmp/delete-shipping.component.sh when: destroy + shipping.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + shipping.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: shipping.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-shipping.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DISABLE_PROFILER="{{ SELF.disable_profiler }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shipping.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-shipping.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-shipping.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shipping.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-shipping.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-shipping.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-shipping.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-shipping.component.sh + - sudo bash /tmp/configure-shipping.component.sh + - sudo bash /tmp/start-shipping.component.sh + - inline: + - sudo bash /tmp/stop-shipping.component.sh + - sudo bash /tmp/delete-shipping.component.sh + when: destroy shipping.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: shipping.component metadata: @@ -2738,12 +4790,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/technology-rules.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/technology-rules.yaml index 527f8fd3c3..b2587923ee 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/technology-rules.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/technology-rules.yaml @@ -4,6 +4,20 @@ # ################################################### +- technology: ansible + component: docker.engine + hosting: + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. + details: '"ansible.builtin.shell", "ansible.builtin.group", and "ansible.builtin.user" tasks' +- technology: terraform + component: docker.engine + hosting: + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local-exec" provider' - technology: ansible component: docker.engine hosting: @@ -51,6 +65,20 @@ weight: 0.5 reason: Kubernetes is more specialized. details: '"kubernetes_service_v1" resource' +- technology: ansible + component: ingress + hosting: + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. + details: '"ansible.builtin.apt_key", "ansible.builtin.apt_repository", "ansible.builtin.apt", "ansible.builtin.copy", and "ansible.builtin.systemd" tasks' +- technology: terraform + component: ingress + hosting: + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" resource to create the installation script and "terraform_data" to execute the script using the "local-exec" provisioner' - technology: ansible component: ingress hosting: @@ -65,6 +93,30 @@ weight: 0 reason: Ansible is more specialized. Also using provisioners is a "last resort". details: '"terraform_data" resource with an "ssh" connection to the virtual machine to copy the install script using the "file" provisioner on the virtual machine and to execute the script using the "remote-exec" provisioner' +- technology: ansible + component: mysql.database + hosting: + - mysql.dbms + - docker.engine + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: compose + component: mysql.database + hosting: + - mysql.dbms + - docker.engine + - local.machine + weight: 0 + reason: One-time use docker container ("fake Kubernetes job") with imperative parts, while other technologies provide declarative modules. +- technology: terraform + component: mysql.database + hosting: + - mysql.dbms + - docker.engine + - local.machine + weight: 1 + reason: Terraform provides a declarative module. - technology: ansible component: mysql.database hosting: @@ -124,6 +176,20 @@ - kubernetes.cluster weight: 0 reason: Ansible is more specialized. +- technology: ansible + component: mysql.database + hosting: + - mysql.dbms + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: terraform + component: mysql.database + hosting: + - mysql.dbms + - local.machine + weight: 1 + reason: Terraform provides a declarative module. - technology: ansible component: mysql.database hosting: @@ -138,6 +204,33 @@ - remote.machine weight: 0.5 reason: Terraform provides a declarative module. However, Terraform requires an SSH workaround. Ansible is more specialized. +- technology: ansible + component: mysql.dbms + artifact: dbms.image + hosting: + - docker.engine + - local.machine + weight: 0.5 + reason: Docker Compose is more specialized + details: '"community.docker.docker_container" task' +- technology: compose + component: mysql.dbms + artifact: dbms.image + hosting: + - docker.engine + - local.machine + weight: 1 + reason: Docker is the underlying technology. + details: docker-compose manifest generated and applied +- technology: terraform + component: mysql.dbms + artifact: dbms.image + hosting: + - docker.engine + - local.machine + weight: 0.5 + reason: Docker Compose is more specialized. + details: '"docker_container" and "docker_image" resources' - technology: ansible component: mysql.dbms artifact: dbms.image @@ -205,6 +298,22 @@ weight: 0.5 reason: Kubernetes is more specialized. details: '"kubernetes_deployment_v1" and "kubernetes_service_v1" resources' +- technology: ansible + component: mysql.dbms + artifact: dbms.image + hosting: + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. + details: '"ansible.builtin.apt", "ansible.builtin.systemd", "ansible.builtin.copy", "ansible.builtin.lineinfile", and "community.mysql.mysql_user" tasks' +- technology: terraform + component: mysql.dbms + artifact: dbms.image + hosting: + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" resource to create the installation script and "terraform_data" to execute the script using the "local-exec" provisioner' - technology: ansible component: mysql.dbms artifact: dbms.image @@ -221,6 +330,204 @@ weight: 0 reason: Ansible is more specialized. Also using provisioners is a "last resort". details: '"terraform_data" resource with an "ssh" connection to the virtual machine to copy the install script using the "file" provisioner on the virtual machine and to execute the script using the "remote-exec" provisioner' +- technology: ansible + component: object.storage + hosting: + - gcp.cloudstorage + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: terraform + component: object.storage + hosting: + - gcp.cloudstorage + weight: 1 + reason: Terraform provides a declarative module. +- technology: ansible + component: object.storage + hosting: + - minio.server + - docker.engine + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: compose + component: object.storage + hosting: + - minio.server + - docker.engine + - local.machine + weight: 0 + reason: One-time use docker container ("fake Kubernetes job") with imperative parts, while other technologies provide declarative modules. +- technology: terraform + component: object.storage + hosting: + - minio.server + - docker.engine + - local.machine + weight: 1 + reason: Terraform provides a declarative module. +- technology: ansible + component: object.storage + hosting: + - minio.server + - docker.engine + - remote.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: compose + component: object.storage + hosting: + - minio.server + - docker.engine + - remote.machine + weight: 0 + reason: One-time use docker container ("fake Kubernetes job") with imperative parts, while other technologies provide declarative modules. +- technology: terraform + component: object.storage + hosting: + - minio.server + - docker.engine + - remote.machine + weight: 0.5 + reason: Terraform provides a declarative module. However, Terraform requires an SSH workaround. Ansible is more specialized. +- technology: ansible + component: object.storage + hosting: + - minio.server + - kubernetes.cluster + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: kubernetes + component: object.storage + hosting: + - minio.server + - kubernetes.cluster + weight: 0 + reason: Kubernetes Job with imperative parts, while declarative other technologies provide declarative modules. +- technology: terraform + component: object.storage + hosting: + - minio.server + - kubernetes.cluster + weight: 0 + reason: Ansible is more specialized. +- technology: ansible + component: redis.server + artifact: cache.image + hosting: + - docker.engine + - local.machine + weight: 0.5 + reason: Docker Compose is more specialized. + details: '"community.docker.docker_container" task' +- technology: compose + component: redis.server + artifact: cache.image + hosting: + - docker.engine + - local.machine + weight: 1 + reason: Docker is the underlying technology. + details: docker compose manifest generated and applied +- technology: terraform + component: redis.server + artifact: cache.image + hosting: + - docker.engine + - local.machine + weight: 0.5 + reason: Docker Compose is more specialized. + details: '"docker_container" and "docker_image" resources' +- technology: ansible + component: redis.server + artifact: cache.image + hosting: + - docker.engine + - remote.machine + weight: 0.5 + reason: Docker Compose is more specialized. + details: '"community.docker.docker_container" task' +- technology: compose + component: redis.server + artifact: cache.image + hosting: + - docker.engine + - remote.machine + weight: 1 + reason: Docker is the underlying technology. + details: docker compose manifest generated and applied +- technology: terraform + component: redis.server + artifact: cache.image + hosting: + - docker.engine + - remote.machine + weight: 0.5 + reason: Docker Compose is more specialized. + details: '"docker_container" and "docker_image" resources' +- technology: ansible + component: redis.server + artifact: cache.image + hosting: + - gcp.memorystore + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: terraform + component: redis.server + artifact: cache.image + hosting: + - gcp.memorystore + weight: 1 + reason: Terraform provides a declarative module. +- technology: ansible + component: redis.server + artifact: cache.image + hosting: + - kubernetes.cluster + weight: 0.5 + reason: Kubernetes is more specialized. +- technology: kubernetes + component: redis.server + artifact: cache.image + hosting: + - kubernetes.cluster + weight: 1 + reason: Kubernetes is the underlying technology. + details: Kubernetes manifest generated and applied +- technology: terraform + component: redis.server + artifact: cache.image + hosting: + - kubernetes.cluster + weight: 0.5 + reason: Kubernetes is more specialized. +- technology: ansible + component: service.application + artifact: docker.image + hosting: + - docker.engine + - local.machine + weight: 0.5 + reason: Docker Compose is more specialized. + details: '"community.docker.docker_container" task' +- technology: compose + component: service.application + artifact: docker.image + hosting: + - docker.engine + - local.machine + weight: 1 + reason: Docker is the underlying technology. + details: docker compose manifest generated and applied +- technology: terraform + component: service.application + artifact: docker.image + hosting: + - docker.engine + - local.machine + weight: 0.5 + reason: Docker Compose is more specialized. + details: '"docker_container" and "docker_image" resources' - technology: ansible component: service.application artifact: docker.image @@ -288,6 +595,24 @@ weight: 0.5 reason: Kubernetes is more specialized. details: '"kubernetes_deployment_v1" and "kubernetes_service_v1" resources' +- technology: ansible + component: service.application + artifact: tar.archive + hosting: + - '*' + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. Special integration for systemd. + details: '"ansible.builtin.file", "ansible.builtin.unarchive", "ansible.builtin.copy", "ansible.builtin.fail", "ansible.builtin.shell", and "ansible.builtin.systemd" tasks with "when" statements' +- technology: terraform + component: service.application + artifact: tar.archive + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts.' - technology: ansible component: service.application artifact: tar.archive @@ -306,6 +631,24 @@ weight: 0 reason: Ansible is more specialized. Also using provisioners is a "last resort". details: '"file" provisioner to upload artifacts and scripts and "remote-exec" to execute scripts' +- technology: ansible + component: service.application + artifact: zip.archive + hosting: + - '*' + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. Special integration for systemd. + details: '"ansible.builtin.file", "ansible.builtin.unarchive", "ansible.builtin.copy", "ansible.builtin.fail", "ansible.builtin.shell", and "ansible.builtin.systemd" tasks with "when" statements' +- technology: terraform + component: service.application + artifact: zip.archive + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts.' - technology: ansible component: service.application artifact: zip.archive @@ -340,6 +683,24 @@ weight: 1 reason: Terraform provides a declarative module. details: '"google_app_engine_standard_app_version", "google_project_iam_member", "google_service_account", "google_storage_bucket", and "google_storage_bucket_object" resources' +- technology: ansible + component: software.application + artifact: apt.package + hosting: + - '*' + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. + details: '"ansible.builtin.shell", "ansible.builtin.apt_key", "ansible.builtin.apt_repository", "ansible.builtin.apt", and "ansible.builtin.copy", tasks with "when" statements' +- technology: terraform + component: software.application + artifact: apt.package + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts' - technology: ansible component: software.application artifact: apt.package @@ -351,13 +712,31 @@ details: '"ansible.builtin.shell", "ansible.builtin.apt_key", "ansible.builtin.apt_repository", "ansible.builtin.apt", and "ansible.builtin.copy", tasks with "when" statements' - technology: terraform component: software.application - artifact: apt.archive + artifact: apt.package hosting: - '*' - remote.machine weight: 0 reason: Ansible is more specialized. Also using provisioners is a "last resort". details: '"file" provisioner to upload scripts and "remote-exec" to execute scripts' +- technology: ansible + component: software.application + artifact: tar.archive + hosting: + - '*' + - local.machine + weight: 0.5 + reason: While this is a primary use case due to the specialization of Ansible, we must rely on scripts. More specialized types should be used, e.g., service.application. + details: '"ansible.builtin.apt", "ansible.builtin.file", "ansible.builtin.unarchive", "ansible.builtin.copy", "ansible.builtin.fail", and "ansible.builtin.shell" tasks with "when" statements' +- technology: terraform + component: software.application + artifact: tar.archive + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts' - technology: ansible component: software.application artifact: tar.archive @@ -376,6 +755,24 @@ weight: 0 reason: Ansible is more specialized. Also using provisioners is a "last resort". details: '"file" provisioner to upload artifacts and scripts and "remote-exec" to execute scripts' +- technology: ansible + component: software.application + artifact: zip.archive + hosting: + - '*' + - local.machine + weight: 0.5 + reason: While this is a primary use case due to the specialization of Ansible, we must rely on scripts. More specialized types should be used, e.g., service.application. + details: '"ansible.builtin.apt", "ansible.builtin.file", "ansible.builtin.unarchive", "ansible.builtin.copy", "ansible.builtin.fail", and "ansible.builtin.shell" tasks with "when" statements' +- technology: terraform + component: software.application + artifact: zip.archive + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts.' - technology: ansible component: software.application artifact: zip.archive diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/tosca-vintner-profile-core.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/tosca-vintner-profile-core.yaml index bcadd5c029..8bbae12e3c 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/tosca-vintner-profile-core.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/tosca-vintner-profile-core.yaml @@ -72,6 +72,9 @@ artifact_types: dbms.image: derived_from: artifact description: expects image reference in "file" + cache.image: + derived_from: artifact + description: expects image reference in "file" interface_types: interface: derived_from: tosca.interfaces.Root @@ -230,10 +233,16 @@ node_types: properties: machine_name: type: string + attributes: + application_address: + type: string + management_address: + type: string local.machine: derived_from: machine metadata: vintner_normative: 'true' + vintner_abstract: 'true' capabilities: host: type: tosca.capabilities.Compute @@ -259,13 +268,6 @@ node_types: type: string ssh_key_file: type: string - attributes: - management_address: - type: string - application_address: - type: string - default: - eval: .::management_address capabilities: host: type: tosca.capabilities.Compute @@ -275,6 +277,10 @@ node_types: connection: ssh host: eval: .parent::management_address + attributes: + application_address: + default: + eval: .::management_address virtual.machine: derived_from: remote.machine physical.machine: @@ -284,6 +290,10 @@ node_types: metadata: vintner_normative: 'true' vintner_abstract: 'true' + requirements: + - host: + capability: tosca.capabilities.Compute + relationship: tosca.relationships.HostedOn relational.database: derived_from: database metadata: @@ -299,6 +309,59 @@ node_types: metadata: vintner_normative: 'true' vintner_abstract: 'true' + cache: + derived_from: software.application + properties: + cache_name: + type: string + cache_port: + type: string + attributes: + application_endpoint: + type: string + default: + concat: + - eval: .::application_protocol + - '://' + - eval: .::application_address + - ':' + - eval: .::application_port + application_address: + type: string + storage: + derived_from: node + metadata: + vintner_normative: 'true' + block.storage: + derived_from: storage + metadata: + vintner_normative: 'true' + object.storage: + derived_from: storage + metadata: + vintner_normative: 'true' + properties: + storage_name: + type: string + storage_dialect: + type: string + storage_user: + type: string + storage_token: + type: string + attributes: + storage_endpoint: + type: string + storage_token: + type: string + requirements: + - host: + capability: tosca.capabilities.Compute + relationship: tosca.relationships.HostedOn + file.storage: + derived_from: storage + metadata: + vintner_normative: 'true' ingress: derived_from: node metadata: @@ -549,32 +612,20 @@ node_types: openstack_networking_secgroup_v2: ports: - name: '{{ SELF.machine_name }}' - ingress~ingress::ansible@kubernetes.cluster: - derived_from: ingress + cache~software.application#apt.package::ansible@*->local.machine: + derived_from: cache metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: + application_directory: type: string default: - get_input: k8s_client_key_file - attributes: - application_address: - type: string - default: not implemented + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -582,122 +633,180 @@ node_types: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - K8S_AUTH_HOST: - eval: .::k8s_host - K8S_AUTH_SSL_CA_CERT: - eval: .::k8s_ca_cert_file - K8S_AUTH_CERT_FILE: - eval: .::k8s_client_cert_file - K8S_AUTH_KEY_FILE: - eval: .::k8s_client_key_file inputs: playbook: q: - - name: apply service - kubernetes.core.k8s: - definition: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.application_name }}-external' - namespace: default - spec: - ports: - - name: '{{ SELF.application_protocol }}' - port: 80 - targetPort: '{{ SELF.application_port }}' - selector: - app: '{{ SELF.application_name }}' - type: LoadBalancer - ingress~ingress::kubernetes@kubernetes.cluster: - derived_from: ingress - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: - type: string - default: - get_input: k8s_client_key_file - attributes: - application_address: - type: string - default: not implemented - interfaces: - Standard: - operations: - create: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: touch manifest - register: manifest - ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.ingress.manifest.yaml' - - name: create manifest + - name: copy management operation ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: '{{ service | to_yaml }}' - vars: - service: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.application_name }}-external' - spec: - ports: - - name: '{{ SELF.application_protocol }}' - port: '{{ SELF.application_port }}' - targetPort: '{{ SELF.application_port }}' - selector: - app: '{{ SELF.application_name }}' - type: LoadBalancer - - name: apply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh args: - executable: /usr/bin/bash - ingress~ingress::terraform@kubernetes.cluster: - derived_from: ingress + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + cache~software.application#apt.package::terraform@*->local.machine: + derived_from: cache metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: + application_directory: type: string default: - get_input: k8s_client_key_file - attributes: - application_address: - type: string - default: not implemented + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -710,32 +819,3316 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - kubernetes: - source: hashicorp/kubernetes - version: 2.31.0 - required_version: '>= 0.14.0' - provider: - kubernetes: - - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} - client_key: ${file("{{ SELF.k8s_client_key_file }}")} - cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} - host: '{{ SELF.k8s_host }}' resource: - kubernetes_service_v1: - application: - - metadata: - - name: '{{ SELF.application_name }}-external' - wait_for_load_balancer: false - spec: - - port: - - name: '{{ SELF.application_protocol }}' - port: 80 - target_port: '{{ SELF.application_port }}' - selector: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-cache.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cache.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-cache.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-cache.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-cache.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-cache.sh + - sudo bash /tmp/configure-cache.sh + - sudo bash /tmp/start-cache.sh + - inline: + - sudo bash /tmp/stop-cache.sh + - sudo bash /tmp/delete-cache.sh + when: destroy + cache~software.application#apt.package::ansible@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + cache~software.application#apt.package::terraform@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-cache.sh + remote-exec: + - inline: + - sudo bash /tmp/create-cache.sh + - sudo bash /tmp/configure-cache.sh + - sudo bash /tmp/start-cache.sh + - inline: + - sudo bash /tmp/stop-cache.sh + - sudo bash /tmp/delete-cache.sh + when: destroy + cache~software.application#tar.archive::ansible@*->local.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + cache~software.application#tar.archive::terraform@*->local.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-cache + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cache {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-cache -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-cache.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cache.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-cache.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-cache.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-cache.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-cache.sh + - sudo bash /tmp/configure-cache.sh + - sudo bash /tmp/start-cache.sh + - inline: + - sudo bash /tmp/stop-cache.sh + - sudo bash /tmp/delete-cache.sh + when: destroy + cache~software.application#tar.archive::ansible@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + cache~software.application#tar.archive::terraform@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-cache + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cache {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-cache -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-cache.sh + remote-exec: + - inline: + - sudo bash /tmp/create-cache.sh + - sudo bash /tmp/configure-cache.sh + - sudo bash /tmp/start-cache.sh + - inline: + - sudo bash /tmp/stop-cache.sh + - sudo bash /tmp/delete-cache.sh + when: destroy + cache~software.application#zip.archive::ansible@*->local.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + cache~software.application#zip.archive::terraform@*->local.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-cache + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cache {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-cache -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-cache.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cache.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-cache.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-cache.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-cache.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-cache.sh + - sudo bash /tmp/configure-cache.sh + - sudo bash /tmp/start-cache.sh + - inline: + - sudo bash /tmp/stop-cache.sh + - sudo bash /tmp/delete-cache.sh + when: destroy + cache~software.application#zip.archive::ansible@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + cache~software.application#zip.archive::terraform@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-cache + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cache {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-cache -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-cache.sh + remote-exec: + - inline: + - sudo bash /tmp/create-cache.sh + - sudo bash /tmp/configure-cache.sh + - sudo bash /tmp/start-cache.sh + - inline: + - sudo bash /tmp/stop-cache.sh + - sudo bash /tmp/delete-cache.sh + when: destroy + object.storage~object.storage::ansible@gcp.cloudstorage: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + attributes: + storage_endpoint: + type: string + default: '{{ SELF.storage_name }}' + storage_token: + type: string + default: '' + storage_dialect: + type: string + default: gcp + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: create bucket + google.cloud.gcp_storage_bucket: + name: '{{ SELF.storage_name }}' + location: EU + project: '{{ SELF.gcp_project }}' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: delete bucket + google.cloud.gcp_storage_bucket: + name: '{{ SELF.storage_name }}' + project: '{{ SELF.gcp_project }}' + state: absent + object.storage~object.storage::terraform@gcp.cloudstorage: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + attributes: + storage_endpoint: + type: string + default: '{{ SELF.storage_name }}' + storage_token: + type: string + default: '' + storage_dialect: + type: string + default: gcp + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + environment: + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file + delete: + implementation: + primary: Terraform + environment: + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_storage_bucket: + bucket: + - name: '{{ SELF.storage_name }}' + location: EU + force_destroy: true + object.storage~object.storage::ansible@minio.server->docker.engine->local.machine: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: create bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: delete policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + object.storage~object.storage::compose@minio.server->docker.engine->local.machine: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.database.compose.yaml.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + services: + job: + container_name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc mb minio/{{ SELF.storage_name }} && mc admin user add minio {{ SELF.storage_user }} {{ SELF.storage_token }} && mc admin policy attach minio readwrite user={{ SELF.storage_user }} + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.database.compose.yaml.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + services: + job: + container_name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc admin policy detach minio readwrite user={{ SELF.storage_user }} && mc admin user rm minio {{ SELF.storage_user }} && mc rm --recursive minio/{{ SELF.storage_name }} + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + object.storage~object.storage::terraform@minio.server->docker.engine->local.machine: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - minio: + source: aminueza/minio + version: 2.5.0 + required_version: '>= 0.14.0' + provider: + minio: + - minio_server: '{{ HOST.application_endpoint }}' + minio_user: '{{ HOST.access_key }}' + minio_password: '{{ HOST.secret_key }}' + resource: + minio_s3_bucket: + bucket: + - bucket: '{{ SELF.storage_name }}' + minio_iam_user: + user: + - name: '{{ SELF.storage_user }}' + secret: '{{ SELF.storage_token }}' + minio_iam_policy: + depends_on: + - minio_s3_bucket.bucket + - minio_iam_user.user + policy: + - name: '{{ SELF.storage_user }}' + policy: '{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*"], "Principal": "{{ SELF.storage_user }}", "Resource": "arn:aws:s3:::*" } ] }' + object.storage~object.storage::ansible@minio.server->docker.engine->remote.machine: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: delete policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + object.storage~object.storage::compose@minio.server->docker.engine->remote.machine: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + services: + job: + container_name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc mb minio/{{ SELF.storage_name }} && mc admin user add minio {{ SELF.storage_user }} {{ SELF.storage_token }} && mc admin policy attach minio readwrite user={{ SELF.storage_user }} + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + services: + job: + container_name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc admin policy detach minio readwrite user={{ SELF.storage_user }} && mc admin user rm minio {{ SELF.storage_user }} && mc rm --recursive minio/{{ SELF.storage_name }} + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + object.storage~object.storage::terraform@minio.server->docker.engine->remote.machine: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - minio: + source: aminueza/minio + version: 2.5.0 + ssh: + source: AndrewChubatiuk/ssh + version: 0.2.3 + required_version: '>= 0.14.0' + data: + ssh_tunnel: + mysql: + - remote: + host: '{{ HOST.application_address }}' + port: '{{ HOST.application_port }}' + provider: + minio: + - minio_server: '{{ HOST.application_endpoint }}' + minio_user: '{{ HOST.access_key }}' + minio_password: '{{ HOST.secret_key }}' + ssh: + - auth: + private_key: + content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} + server: + host: '{{ HOST.management_address }}' + port: 22 + user: '{{ SELF.os_ssh_user }}' + resource: + minio_s3_bucket: + bucket: + - bucket: '{{ SELF.storage_name }}' + minio_iam_user: + user: + - name: '{{ SELF.storage_user }}' + secret: '{{ SELF.storage_token }}' + minio_iam_policy: + depends_on: + - minio_s3_bucket.bucket + - minio_iam_user.user + policy: + - name: '{{ SELF.storage_user }}' + policy: '{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*"], "Principal": "{{ SELF.storage_user }}", "Resource": "arn:aws:s3:::*" } ] }' + object.storage~object.storage::ansible@minio.server->kubernetes.cluster: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: create bucket + block: + - name: forward port + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.cache_name }} {{ HOST.cache_port }}:{{ HOST.cache_port }} + args: + executable: /usr/bin/bash + async: 30 + poll: 0 + - name: create bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + always: + - name: unforward port + ansible.builtin.shell: pkill -f "port-forward service/{{ HOST.cache_name }}" + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: delete bucket + block: + - name: forward port + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.cache_name }} {{ HOST.cache_port }}:{{ HOST.cache_port }} + args: + executable: /usr/bin/bash + async: 30 + poll: 0 + - name: delete policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + always: + - name: unforward port + ansible.builtin.shell: pkill -f "port-forward service/{{ HOST.cache_name }}" + args: + executable: /usr/bin/bash + object.storage~object.storage::kubernetes@minio.server->kubernetes.cluster: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.object-storage.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: '{{ job | to_yaml }}' + vars: + job: + apiVersion: batch/v1 + kind: Job + metadata: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + spec: + template: + spec: + restartPolicy: Never + containers: + - name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc mb minio/{{ SELF.storage_name }} && mc admin user add minio {{ SELF.storage_user }} {{ SELF.storage_token }} && mc admin policy attach minio readwrite user={{ SELF.storage_user }} + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.storage_name }}-{{ HOST.cache_name }} + args: + executable: /usr/bin/bash + - name: cleanup + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.object-storage.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: '{{ job | to_yaml }}' + vars: + job: + apiVersion: batch/v1 + kind: Job + metadata: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + spec: + template: + spec: + restartPolicy: Never + containers: + - name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc admin policy detach minio readwrite user={{ SELF.storage_user }} && mc admin user rm minio {{ SELF.storage_user }} && mc rm --recursive minio/{{ SELF.storage_name }} + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.storage_name }}-{{ HOST.cache_name }} + args: + executable: /usr/bin/bash + - name: cleanup + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + object.storage~object.storage::terraform@minio.server->kubernetes.cluster: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: [] + provider: {} + resource: + terraform_data: + forward_port: + - input: 127.0.0.1:{{ HOST.cache_port }} + provisioner: + local-exec: + command: |- + (nohup kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.cache_name }} {{ HOST.cache_port }}:{{ HOST.cache_port }} > /dev/null 2>&1 &) + sleep 5s + interpreter: + - /bin/bash + - '-c' + unforward_port: + - depends_on: + - minio_iam_policy.policy + provisioner: + local-exec: + command: pkill -f "port-forward service/{{ HOST.cache_name }}" + interpreter: + - /bin/bash + - '-c' + minio_s3_bucket: + bucket: + - bucket: '{{ SELF.storage_name }}' + minio_iam_user: + user: + - name: '{{ SELF.storage_user }}' + secret: '{{ SELF.storage_token }}' + minio_iam_policy: + depends_on: + - minio_s3_bucket.bucket + - minio_iam_user.user + policy: + - name: '{{ SELF.storage_user }}' + policy: '{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*"], "Principal": "{{ SELF.storage_user }}", "Resource": "arn:aws:s3:::*" } ] }' + ingress~ingress::ansible@kubernetes.cluster: + derived_from: ingress + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: not implemented + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file + inputs: + playbook: + q: + - name: apply service + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}-external' + namespace: default + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: 80 + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: LoadBalancer + ingress~ingress::kubernetes@kubernetes.cluster: + derived_from: ingress + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: not implemented + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.ingress.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: '{{ service | to_yaml }}' + vars: + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}-external' + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: LoadBalancer + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + ingress~ingress::terraform@kubernetes.cluster: + derived_from: ingress + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: not implemented + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - kubernetes: + source: hashicorp/kubernetes + version: 2.31.0 + required_version: '>= 0.14.0' + provider: + kubernetes: + - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} + client_key: ${file("{{ SELF.k8s_client_key_file }}")} + cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} + host: '{{ SELF.k8s_host }}' + resource: + kubernetes_service_v1: + application: + - metadata: + - name: '{{ SELF.application_name }}-external' + wait_for_load_balancer: false + spec: + - port: + - name: '{{ SELF.application_protocol }}' + port: 80 + target_port: '{{ SELF.application_port }}' + selector: app: '{{ SELF.application_name }}' type: LoadBalancer + ingress~ingress::ansible@local.machine: + derived_from: ingress + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::application_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: add apt key + ansible.builtin.apt_key: + url: https://dl.cloudsmith.io/public/caddy/stable/gpg.key + keyring: /usr/share/keyrings/caddy-stable-archive-keyring.gpg + state: present + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/caddy-stable-archive-keyring.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main + filename: caddy-stable + state: present + - name: install package + ansible.builtin.apt: + name: caddy + state: present + update_cache: 'yes' + - name: configure caddy + ansible.builtin.copy: + dest: /etc/caddy/Caddyfile + content: | + :80 { + reverse_proxy localhost:{{ SELF.application_port }} + } + - name: restart caddy + ansible.builtin.systemd: + name: caddy + state: reloaded + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: uninstall package + ansible.builtin.apt: + name: caddy + state: absent + ingress~ingress::terraform@local.machine: + derived_from: ingress + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::application_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_script: + content: | + + #!/usr/bin/bash + set -e + + # Install caddy + apt-get install -y debian-keyring debian-archive-keyring apt-transport-https curl + curl -1sLf https://dl.cloudsmith.io/public/caddy/stable/gpg.key | gpg --dearmor --yes -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg + curl -1sLf https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt | tee /etc/apt/sources.list.d/caddy-stable.list + apt-get update + apt-get install caddy -y + + # Configure caddy + cat < /etc/caddy/Caddyfile + :80 { + reverse_proxy localhost:{{ SELF.application_port }} + } + EOF + + # Restart caddy + systemctl reload caddy + destination: /tmp/install-ingress.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_script + provisioner: + local-exec: + - inline: + - sudo bash /tmp/install-ingress.sh ingress~ingress::ansible@remote.machine: derived_from: ingress metadata: diff --git a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/tosca-vintner-profile-extended.yaml b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/tosca-vintner-profile-extended.yaml index 3750f5c5ea..ea43ed49ee 100644 --- a/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/tosca-vintner-profile-extended.yaml +++ b/examples/unfurl-technology---boutique---plus-maintenance-automated/lib/tosca-vintner-profile-extended.yaml @@ -99,6 +99,15 @@ node_types: operations: configure: npm ci start: npm start + reactjs.service.application: + derived_from: service.application + metadata: + vintner_normative: 'true' + vintner_abstract: 'true' + properties: + application_language: + type: string + default: nodejs18 python.runtime: derived_from: software.runtime metadata: @@ -312,6 +321,30 @@ node_types: gcp_service: type: string default: cloudbuild.googleapis.com + gcp.kubernetesengine: + derived_from: gcp.service + metadata: + vintner_normative: 'true' + properties: + gcp_service: + type: string + default: container.googleapis.com + gcp.cloudstorage: + derived_from: gcp.service + metadata: + vintner_normative: 'true' + properties: + gcp_service: + type: string + default: storage.googleapis.com + gcp.memorystore: + derived_from: gcp.service + metadata: + vintner_normative: 'true' + properties: + gcp_service: + type: string + default: redis.googleapis.com docker.engine: derived_from: container.runtime description: Installs Docker Engine listening on the unix socket as well as on tcp://0.0.0.0:2375 @@ -450,6 +483,33 @@ node_types: - host: capability: tosca.capabilities.Compute relationship: tosca.relationships.HostedOn + minio.server: + derived_from: service.application + metadata: + vintner_normative: 'true' + properties: + access_key: + type: string + metadata: + vintner_name: MINIO_ROOT_USER + secret_key: + type: string + metadata: + vintner_name: MINIO_ROOT_PASSWORD + redis.server: + derived_from: cache + metadata: + vintner_normative: 'true' + properties: + application_protocol: + type: string + default: redis + application_name: + default: + eval: .::cache_name + application_port: + default: + eval: .::cache_port # [OPENTOSCA_VINTNER_GENERATION_MARK] @@ -459,20 +519,12 @@ node_types: # ################################################################ - nodejs.runtime~software.application#apt.package::ansible@*->remote.machine: + nodejs.runtime~software.application#apt.package::ansible@*->local.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -487,14 +539,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: run setup script ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - args: @@ -545,21 +593,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -576,21 +616,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -607,21 +643,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -638,21 +670,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -677,27 +701,11 @@ node_types: ansible.builtin.apt: name: '{{ ".artifacts::apt_package::file" | eval }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - nodejs.runtime~software.application#apt.archive::terraform@*->remote.machine: + nodejs.runtime~software.application#apt.package::terraform@*->local.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -719,31 +727,457 @@ node_types: inputs: main: resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-nodejs.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-nodejs.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-nodejs.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-nodejs.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-nodejs.runtime.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - content: | - #!/usr/bin/bash - set -e - - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-nodejs.runtime.sh + - sudo bash /tmp/configure-nodejs.runtime.sh + - sudo bash /tmp/start-nodejs.runtime.sh + - inline: + - sudo bash /tmp/stop-nodejs.runtime.sh + - sudo bash /tmp/delete-nodejs.runtime.sh + when: destroy + nodejs.runtime~software.application#apt.package::ansible@*->remote.machine: + derived_from: nodejs.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + nodejs.runtime~software.application#apt.package::terraform@*->remote.machine: + derived_from: nodejs.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} fi @@ -766,14 +1200,6 @@ node_types: APPLICATION_NAME="{{ SELF.application_name }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -878,20 +1304,12 @@ node_types: - sudo bash /tmp/stop-nodejs.runtime.sh - sudo bash /tmp/delete-nodejs.runtime.sh when: destroy - nodejs.runtime~software.application#tar.archive::ansible@*->remote.machine: + nodejs.runtime~software.application#tar.archive::ansible@*->local.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -906,14 +1324,16 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - name: wait for ssh wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -955,16 +1375,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -986,16 +1400,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1021,16 +1429,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1056,16 +1458,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1091,27 +1487,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - nodejs.runtime~software.application#tar.archive::terraform@*->remote.machine: + nodejs.runtime~software.application#tar.archive::terraform@*->local.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1133,143 +1513,151 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-nodejs.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-nodejs.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-nodejs.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-nodejs.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-nodejs.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-nodejs.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-nodejs.runtime.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-nodejs.runtime - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-nodejs.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-nodejs.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-nodejs.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-nodejs.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-nodejs.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-nodejs.runtime.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-nodejs.runtime.sh - sudo bash /tmp/configure-nodejs.runtime.sh @@ -1278,7 +1666,7 @@ node_types: - sudo bash /tmp/stop-nodejs.runtime.sh - sudo bash /tmp/delete-nodejs.runtime.sh when: destroy - nodejs.runtime~software.application#zip.archive::ansible@*->remote.machine: + nodejs.runtime~software.application#tar.archive::ansible@*->remote.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' @@ -1314,26 +1702,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1498,7 +1883,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - nodejs.runtime~software.application#zip.archive::terraform@*->remote.machine: + nodejs.runtime~software.application#tar.archive::terraform@*->remote.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' @@ -1545,9 +1930,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-nodejs.runtime - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e @@ -1561,12 +1946,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-nodejs.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-nodejs.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1681,20 +2066,12 @@ node_types: - sudo bash /tmp/stop-nodejs.runtime.sh - sudo bash /tmp/delete-nodejs.runtime.sh when: destroy - python.runtime~software.application#apt.package::ansible@*->remote.machine: - derived_from: python.runtime + nodejs.runtime~software.application#zip.archive::ansible@*->local.machine: + derived_from: nodejs.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -1709,48 +2086,39 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: run setup script - ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - args: - executable: /bin/bash - when: '".artifacts::apt_package::script" | eval != ""' - - name: add apt key - ansible.builtin.apt_key: - url: '{{ ".artifacts::apt_package::key" | eval }}' - keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - state: present - when: '".artifacts::apt_package::key" | eval != ""' - - name: add apt repository - ansible.builtin.apt_repository: - repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} - filename: '{{ ".artifacts::apt_package::repository" | eval }}' - state: present - when: '".artifacts::apt_package::source" | eval != ""' - - name: update apt cache + - name: install operational dependencies ansible.builtin.apt: + name: unzip update_cache: 'yes' - - name: install dependencies - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' - state: present - when: '".artifacts::apt_package::dependencies" | eval != ""' - - name: install package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: present - environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -1767,21 +2135,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -1798,22 +2158,18 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' content: |- @@ -1829,21 +2185,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1860,21 +2212,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1895,31 +2239,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - - name: uninstall package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - python.runtime~software.application#apt.archive::terraform@*->remote.machine: - derived_from: python.runtime + nodejs.runtime~software.application#zip.archive::terraform@*->local.machine: + derived_from: nodejs.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1941,167 +2265,161 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-nodejs.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-nodejs.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-nodejs.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-nodejs.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-nodejs.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-nodejs.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-nodejs.runtime.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - content: | - #!/usr/bin/bash - set -e - - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi - - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi - - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then - echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} - fi - - # Update apt cache - apt-get update -y - - # Install dependencies - if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then - apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y - fi - - # Install package - {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-python.runtime {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-python.runtime.sh - remote-exec: + local-exec: - inline: - - sudo bash /tmp/create-python.runtime.sh - - sudo bash /tmp/configure-python.runtime.sh - - sudo bash /tmp/start-python.runtime.sh + - sudo bash /tmp/create-nodejs.runtime.sh + - sudo bash /tmp/configure-nodejs.runtime.sh + - sudo bash /tmp/start-nodejs.runtime.sh - inline: - - sudo bash /tmp/stop-python.runtime.sh - - sudo bash /tmp/delete-python.runtime.sh + - sudo bash /tmp/stop-nodejs.runtime.sh + - sudo bash /tmp/delete-nodejs.runtime.sh when: destroy - python.runtime~software.application#tar.archive::ansible@*->remote.machine: - derived_from: python.runtime + nodejs.runtime~software.application#zip.archive::ansible@*->remote.machine: + derived_from: nodejs.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -2136,23 +2454,27 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -2160,7 +2482,7 @@ node_types: - name: create .env file ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' - content: '' + content: APPLICATION_NAME="{{ SELF.application_name }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -2317,8 +2639,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - python.runtime~software.application#tar.archive::terraform@*->remote.machine: - derived_from: python.runtime + nodejs.runtime~software.application#zip.archive::terraform@*->remote.machine: + derived_from: nodejs.runtime metadata: vintner_generated: 'true' properties: @@ -2364,9 +2686,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-python.runtime - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-nodejs.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e @@ -2376,16 +2698,16 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - + APPLICATION_NAME="{{ SELF.application_name }}" EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-python.runtime {{ ".artifacts::tar_archive::file" | eval }} + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::zip_archive::file" | eval }} fi # Extract deployment artifact - tar -xzf /tmp/artifact-python.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + unzip /tmp/artifact-nodejs.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2403,7 +2725,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-python.runtime.sh + destination: /tmp/create-nodejs.runtime.sh - content: | #!/usr/bin/bash set -e @@ -2421,7 +2743,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-python.runtime.sh + destination: /tmp/configure-nodejs.runtime.sh - content: | #!/usr/bin/bash set -e @@ -2445,7 +2767,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-python.runtime.sh + destination: /tmp/start-nodejs.runtime.sh - content: | #!/usr/bin/bash set -e @@ -2469,7 +2791,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-python.runtime.sh + destination: /tmp/stop-nodejs.runtime.sh - content: | #!/usr/bin/bash set -e @@ -2490,30 +2812,22 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-python.runtime.sh + destination: /tmp/delete-nodejs.runtime.sh remote-exec: - inline: - - sudo bash /tmp/create-python.runtime.sh - - sudo bash /tmp/configure-python.runtime.sh - - sudo bash /tmp/start-python.runtime.sh + - sudo bash /tmp/create-nodejs.runtime.sh + - sudo bash /tmp/configure-nodejs.runtime.sh + - sudo bash /tmp/start-nodejs.runtime.sh - inline: - - sudo bash /tmp/stop-python.runtime.sh - - sudo bash /tmp/delete-python.runtime.sh + - sudo bash /tmp/stop-nodejs.runtime.sh + - sudo bash /tmp/delete-nodejs.runtime.sh when: destroy - python.runtime~software.application#zip.archive::ansible@*->remote.machine: + python.runtime~software.application#apt.package::ansible@*->local.machine: derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -2528,42 +2842,44 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: install operational dependencies + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache ansible.builtin.apt: - name: unzip update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -2580,21 +2896,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -2611,21 +2919,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -2646,21 +2946,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "stop" missing @@ -2681,21 +2973,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -2716,27 +3000,15 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - python.runtime~software.application#zip.archive::terraform@*->remote.machine: + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + python.runtime~software.application#apt.package::terraform@*->local.machine: derived_from: python.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -2758,227 +3030,240 @@ node_types: inputs: main: resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-python.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-python.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-python.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-python.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-python.runtime.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-python.runtime - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-python.runtime {{ ".artifacts::zip_archive::file" | eval }} - fi - - # Extract deployment artifact - unzip /tmp/artifact-python.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-python.runtime.sh - remote-exec: - - inline: - - sudo bash /tmp/create-python.runtime.sh - - sudo bash /tmp/configure-python.runtime.sh - - sudo bash /tmp/start-python.runtime.sh - - inline: - - sudo bash /tmp/stop-python.runtime.sh - - sudo bash /tmp/delete-python.runtime.sh - when: destroy - java.runtime~software.application#apt.package::ansible@*->remote.machine: - derived_from: java.runtime - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - application_directory: - type: string - default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name - interfaces: - Standard: - operations: - create: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: run setup script - ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - args: - executable: /bin/bash - when: '".artifacts::apt_package::script" | eval != ""' - - name: add apt key - ansible.builtin.apt_key: - url: '{{ ".artifacts::apt_package::key" | eval }}' - keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - state: present - when: '".artifacts::apt_package::key" | eval != ""' - - name: add apt repository - ansible.builtin.apt_repository: - repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} - filename: '{{ ".artifacts::apt_package::repository" | eval }}' - state: present - when: '".artifacts::apt_package::source" | eval != ""' - - name: update apt cache - ansible.builtin.apt: - update_cache: 'yes' - - name: install dependencies - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' - state: present - when: '".artifacts::apt_package::dependencies" | eval != ""' - - name: install package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: present - environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/create.sh' - content: |- - #!/usr/bin/bash - set -e + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh + - inline: + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh + when: destroy + python.runtime~software.application#apt.package::ansible@*->remote.machine: + derived_from: python.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} mode: '0755' @@ -3035,6 +3320,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -3066,6 +3355,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -3125,8 +3418,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - java.runtime~software.application#apt.archive::terraform@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#apt.package::terraform@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: @@ -3207,16 +3500,8 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-java.runtime {{ ".artifacts::apt_archive::file" | eval }} - fi - # Extract deployment artifact - undefined + EOF>> # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -3234,7 +3519,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-java.runtime.sh + destination: /tmp/create-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -3252,7 +3537,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-java.runtime.sh + destination: /tmp/configure-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -3270,7 +3555,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-java.runtime.sh + destination: /tmp/start-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -3288,7 +3573,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-java.runtime.sh + destination: /tmp/stop-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -3312,30 +3597,22 @@ node_types: # Uninstall package apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-java.runtime.sh + destination: /tmp/delete-python.runtime.sh remote-exec: - inline: - - sudo bash /tmp/create-java.runtime.sh - - sudo bash /tmp/configure-java.runtime.sh - - sudo bash /tmp/start-java.runtime.sh + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh - inline: - - sudo bash /tmp/stop-java.runtime.sh - - sudo bash /tmp/delete-java.runtime.sh + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh when: destroy - java.runtime~software.application#tar.archive::ansible@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#tar.archive::ansible@*->local.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -3350,14 +3627,16 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - name: wait for ssh wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -3382,7 +3661,7 @@ node_types: - name: create .env file ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' - content: APPLICATION_NAME="{{ SELF.application_name }}" + content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -3399,16 +3678,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -3430,16 +3703,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -3465,16 +3732,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -3500,16 +3761,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -3535,27 +3790,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - java.runtime~software.application#tar.archive::terraform@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#tar.archive::terraform@*->local.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -3577,153 +3816,161 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-python.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-python.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-python.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-python.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-python.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-python.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-python.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-python.runtime.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-java.runtime - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-java.runtime {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-java.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-java.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-java.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-java.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-java.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-java.runtime.sh - remote-exec: + local-exec: - inline: - - sudo bash /tmp/create-java.runtime.sh - - sudo bash /tmp/configure-java.runtime.sh - - sudo bash /tmp/start-java.runtime.sh + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh - inline: - - sudo bash /tmp/stop-java.runtime.sh - - sudo bash /tmp/delete-java.runtime.sh + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh when: destroy - java.runtime~software.application#zip.archive::ansible@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#tar.archive::ansible@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -3758,26 +4005,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -3785,7 +4029,7 @@ node_types: - name: create .env file ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' - content: APPLICATION_NAME="{{ SELF.application_name }}" + content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -3942,8 +4186,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - java.runtime~software.application#zip.archive::terraform@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#tar.archive::terraform@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: @@ -3989,9 +4233,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-java.runtime - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-python.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e @@ -4001,16 +4245,16 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-java.runtime {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-python.runtime {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-java.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-python.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -4028,7 +4272,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-java.runtime.sh + destination: /tmp/create-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4046,7 +4290,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-java.runtime.sh + destination: /tmp/configure-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4070,7 +4314,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-java.runtime.sh + destination: /tmp/start-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4094,7 +4338,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-java.runtime.sh + destination: /tmp/stop-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4115,31 +4359,23 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-java.runtime.sh + destination: /tmp/delete-python.runtime.sh remote-exec: - inline: - - sudo bash /tmp/create-java.runtime.sh - - sudo bash /tmp/configure-java.runtime.sh - - sudo bash /tmp/start-java.runtime.sh + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh - inline: - - sudo bash /tmp/stop-java.runtime.sh - - sudo bash /tmp/delete-java.runtime.sh + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh when: destroy - dotnet.runtime~software.application#apt.package::ansible@*->remote.machine: - derived_from: dotnet.runtime + python.runtime~software.application#zip.archive::ansible@*->local.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - application_directory: + application_directory: type: string default: concat: @@ -4153,48 +4389,39 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: run setup script - ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - args: - executable: /bin/bash - when: '".artifacts::apt_package::script" | eval != ""' - - name: add apt key - ansible.builtin.apt_key: - url: '{{ ".artifacts::apt_package::key" | eval }}' - keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - state: present - when: '".artifacts::apt_package::key" | eval != ""' - - name: add apt repository - ansible.builtin.apt_repository: - repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} - filename: '{{ ".artifacts::apt_package::repository" | eval }}' - state: present - when: '".artifacts::apt_package::source" | eval != ""' - - name: update apt cache + - name: install operational dependencies ansible.builtin.apt: + name: unzip update_cache: 'yes' - - name: install dependencies - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' - state: present - when: '".artifacts::apt_package::dependencies" | eval != ""' - - name: install package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: present - environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -4211,21 +4438,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -4242,21 +4461,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -4273,21 +4488,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -4304,21 +4515,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -4339,31 +4542,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - - name: uninstall package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - dotnet.runtime~software.application#apt.archive::terraform@*->remote.machine: - derived_from: dotnet.runtime + python.runtime~software.application#zip.archive::terraform@*->local.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -4385,263 +4568,261 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-python.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-python.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-python.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-python.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-python.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-python.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-python.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-python.runtime.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - content: | - #!/usr/bin/bash - set -e + local-exec: + - inline: + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh + - inline: + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh + when: destroy + python.runtime~software.application#zip.archive::ansible@*->remote.machine: + derived_from: python.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi - - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi - - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then - echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} - fi - - # Update apt cache - apt-get update -y - - # Install dependencies - if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then - apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y - fi - - # Install package - {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-dotnet.runtime.sh - remote-exec: - - inline: - - sudo bash /tmp/create-dotnet.runtime.sh - - sudo bash /tmp/configure-dotnet.runtime.sh - - sudo bash /tmp/start-dotnet.runtime.sh - - inline: - - sudo bash /tmp/stop-dotnet.runtime.sh - - sudo bash /tmp/delete-dotnet.runtime.sh - when: destroy - dotnet.runtime~software.application#tar.archive::ansible@*->remote.machine: - derived_from: dotnet.runtime - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - application_directory: - type: string - default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name - interfaces: - Standard: - operations: - create: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") - - name: extract deployment artifact from URL in application directory - ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: APPLICATION_NAME="{{ SELF.application_name }}" - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/create.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - mode: '0755' - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/create.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - configure: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/configure.sh' - content: |- - #!/usr/bin/bash - set -e + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} mode: '0755' @@ -4761,8 +4942,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - dotnet.runtime~software.application#tar.archive::terraform@*->remote.machine: - derived_from: dotnet.runtime + python.runtime~software.application#zip.archive::terraform@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: @@ -4808,9 +4989,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-dotnet.runtime - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-python.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e @@ -4820,16 +5001,16 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::tar_archive::file" | eval }} + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-python.runtime {{ ".artifacts::zip_archive::file" | eval }} fi # Extract deployment artifact - tar -xzf /tmp/artifact-dotnet.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + unzip /tmp/artifact-python.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -4847,7 +5028,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-dotnet.runtime.sh + destination: /tmp/create-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4865,7 +5046,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-dotnet.runtime.sh + destination: /tmp/configure-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4889,7 +5070,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-dotnet.runtime.sh + destination: /tmp/start-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4913,7 +5094,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-dotnet.runtime.sh + destination: /tmp/stop-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4934,30 +5115,22 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-dotnet.runtime.sh + destination: /tmp/delete-python.runtime.sh remote-exec: - inline: - - sudo bash /tmp/create-dotnet.runtime.sh - - sudo bash /tmp/configure-dotnet.runtime.sh - - sudo bash /tmp/start-dotnet.runtime.sh + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh - inline: - - sudo bash /tmp/stop-dotnet.runtime.sh - - sudo bash /tmp/delete-dotnet.runtime.sh + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh when: destroy - dotnet.runtime~software.application#zip.archive::ansible@*->remote.machine: - derived_from: dotnet.runtime + java.runtime~software.application#apt.package::ansible@*->local.machine: + derived_from: java.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -4972,42 +5145,44 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: install operational dependencies + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache ansible.builtin.apt: - name: unzip update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: APPLICATION_NAME="{{ SELF.application_name }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -5024,21 +5199,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -5055,21 +5222,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -5090,21 +5249,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "stop" missing @@ -5125,21 +5276,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -5160,27 +5303,15 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - dotnet.runtime~software.application#zip.archive::terraform@*->remote.machine: - derived_from: dotnet.runtime + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + java.runtime~software.application#apt.package::terraform@*->local.machine: + derived_from: java.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -5202,37 +5333,478 @@ node_types: inputs: main: resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-java.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-java.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-java.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-java.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-java.runtime.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-dotnet.runtime - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + java.runtime~software.application#apt.package::ansible@*->remote.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e - # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::zip_archive::file" | eval }} + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + java.runtime~software.application#apt.package::terraform@*->remote.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - fi - # Extract deployment artifact - unzip /tmp/artifact-dotnet.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -5250,7 +5822,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-dotnet.runtime.sh + destination: /tmp/create-java.runtime.sh - content: | #!/usr/bin/bash set -e @@ -5268,17 +5840,11 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-dotnet.runtime.sh + destination: /tmp/configure-java.runtime.sh - content: | #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - # Copy operation cat < {{ SELF.application_directory }}/.vintner/start.sh #!/usr/bin/bash @@ -5292,17 +5858,11 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-dotnet.runtime.sh + destination: /tmp/start-java.runtime.sh - content: | #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - # Copy operation cat < {{ SELF.application_directory }}/.vintner/stop.sh #!/usr/bin/bash @@ -5316,7 +5876,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-dotnet.runtime.sh + destination: /tmp/stop-java.runtime.sh - content: | #!/usr/bin/bash set -e @@ -5337,34 +5897,33 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-dotnet.runtime.sh + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-java.runtime.sh remote-exec: - inline: - - sudo bash /tmp/create-dotnet.runtime.sh - - sudo bash /tmp/configure-dotnet.runtime.sh - - sudo bash /tmp/start-dotnet.runtime.sh + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh - inline: - - sudo bash /tmp/stop-dotnet.runtime.sh - - sudo bash /tmp/delete-dotnet.runtime.sh + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh when: destroy - gcp.cloudrun~gcp.service::ansible: - derived_from: gcp.cloudrun + java.runtime~software.application#tar.archive::ansible@*->local.machine: + derived_from: java.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -5372,36 +5931,181 @@ node_types: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.cloudrun~gcp.service::terraform: - derived_from: gcp.cloudrun + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + java.runtime~software.application#tar.archive::terraform@*->local.machine: + derived_from: java.runtime metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -5414,77 +6118,402 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.cloudsql~gcp.service::ansible: - derived_from: gcp.cloudsql + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-java.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-java.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-java.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-java.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-java.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-java.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-java.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-java.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + java.runtime~software.application#tar.archive::ansible@*->remote.machine: + derived_from: java.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.cloudsql~gcp.service::terraform: - derived_from: gcp.cloudsql + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + java.runtime~software.application#tar.archive::terraform@*->remote.machine: + derived_from: java.runtime metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + os_ssh_host: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -5497,77 +6526,13986 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.appengine~gcp.service::ansible: - derived_from: gcp.appengine - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-java.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-java.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-java.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-java.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + java.runtime~software.application#zip.archive::ansible@*->local.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + java.runtime~software.application#zip.archive::terraform@*->local.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-java.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-java.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-java.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-java.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-java.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-java.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-java.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-java.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + java.runtime~software.application#zip.archive::ansible@*->remote.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + java.runtime~software.application#zip.archive::terraform@*->remote.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-java.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-java.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-java.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-java.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + dotnet.runtime~software.application#apt.package::ansible@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + dotnet.runtime~software.application#apt.package::terraform@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-dotnet.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-dotnet.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-dotnet.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-dotnet.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-dotnet.runtime.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#apt.package::ansible@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + dotnet.runtime~software.application#apt.package::terraform@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-dotnet.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#tar.archive::ansible@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + dotnet.runtime~software.application#tar.archive::terraform@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-dotnet.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-dotnet.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-dotnet.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-dotnet.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-dotnet.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-dotnet.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-dotnet.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#tar.archive::ansible@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + dotnet.runtime~software.application#tar.archive::terraform@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-dotnet.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-dotnet.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-dotnet.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#zip.archive::ansible@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + dotnet.runtime~software.application#zip.archive::terraform@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-dotnet.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-dotnet.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-dotnet.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-dotnet.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-dotnet.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-dotnet.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-dotnet.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#zip.archive::ansible@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + dotnet.runtime~software.application#zip.archive::terraform@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-dotnet.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-dotnet.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-dotnet.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + gcp.cloudrun~gcp.service::ansible: + derived_from: gcp.cloudrun + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.cloudrun~gcp.service::terraform: + derived_from: gcp.cloudrun + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.cloudsql~gcp.service::ansible: + derived_from: gcp.cloudsql + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.cloudsql~gcp.service::terraform: + derived_from: gcp.cloudsql + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.appengine~gcp.service::ansible: + derived_from: gcp.appengine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.appengine~gcp.service::terraform: + derived_from: gcp.appengine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.appenginereporting~gcp.service::ansible: + derived_from: gcp.appenginereporting + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.appenginereporting~gcp.service::terraform: + derived_from: gcp.appenginereporting + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.cloudbuild~gcp.service::ansible: + derived_from: gcp.cloudbuild + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.cloudbuild~gcp.service::terraform: + derived_from: gcp.cloudbuild + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.kubernetesengine~gcp.service::ansible: + derived_from: gcp.kubernetesengine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.kubernetesengine~gcp.service::terraform: + derived_from: gcp.kubernetesengine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.cloudstorage~gcp.service::ansible: + derived_from: gcp.cloudstorage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.cloudstorage~gcp.service::terraform: + derived_from: gcp.cloudstorage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.memorystore~gcp.service::ansible: + derived_from: gcp.memorystore + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.memorystore~gcp.service::terraform: + derived_from: gcp.memorystore + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + docker.engine~docker.engine::ansible@local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install docker + ansible.builtin.shell: curl -sSL https://get.docker.com | sh + args: + executable: /usr/bin/bash + - name: update service + ansible.builtin.copy: + dest: /lib/systemd/system/docker.service + content: | + [Unit] + Description=Docker Application Container Engine + Documentation=https://docs.docker.com + After=network-online.target docker.socket firewalld.service containerd.service time-set.target + Wants=network-online.target containerd.service + Requires=docker.socket + + [Service] + Type=notify + ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock + ExecReload=/bin/kill -s HUP $MAINPID + TimeoutStartSec=0 + RestartSec=2 + Restart=always + StartLimitBurst=3 + StartLimitInterval=60s + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + Delegate=yes + KillMode=process + OOMScoreAdjust=-500 + + [Install] + WantedBy=multi-user.target + - name: restart service + ansible.builtin.systemd: + name: docker.service + state: restarted + enabled: 'yes' + daemon_reload: 'yes' + - name: add docker group + ansible.builtin.group: + name: docker + - name: add user to docker group + ansible.builtin.user: + name: '{{ SELF.os_ssh_user }}' + groups: docker + append: 'yes' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: delete docker packages + ansible.builtin.apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + - docker-ce-rootless-extras + state: absent + purge: 'true' + autoremove: 'true' + - name: delete docker directories + ansible.builtin.file: + name: '{{ item }}' + state: absent + loop: + - /var/lib/docker + - /var/lib/containerd + docker.engine~docker.engine::terraform@local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - mysql: + source: hashicorp/local + version: 2.5.1 + required_version: '>= 0.14.0' + resource: + local_file: + tmp_service: + content: | + [Unit] + Description=Docker Application Container Engine + Documentation=https://docs.docker.com + After=network-online.target docker.socket firewalld.service containerd.service time-set.target + Wants=network-online.target containerd.service + Requires=docker.socket + + [Service] + Type=notify + ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock + ExecReload=/bin/kill -s HUP $MAINPID + TimeoutStartSec=0 + RestartSec=2 + Restart=always + StartLimitBurst=3 + StartLimitInterval=60s + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + Delegate=yes + KillMode=process + OOMScoreAdjust=-500 + + [Install] + WantedBy=multi-user.target + filename: /tmp/docker.service + terraform_data: + local: + - depends_on: local_file.tmp_service + provisioner: + local-exec: + - inline: + - curl -sSL https://get.docker.com | sudo sh + - sudo groupadd -f docker + - sudo usermod -aG docker {{ SELF.os_ssh_user }} + - sleep 10s + - cat /tmp/docker.service | sudo tee /lib/systemd/system/docker.service + - sudo systemctl daemon-reload + - sudo systemctl restart docker.service + - inline: + - sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras -y + - sudo rm -rf /var/lib/docker + - sudo rm -rf /var/lib/containerd + when: destroy + docker.engine~docker.engine::ansible@remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install docker + ansible.builtin.shell: curl -sSL https://get.docker.com | sh + args: + executable: /usr/bin/bash + - name: update service + ansible.builtin.copy: + dest: /lib/systemd/system/docker.service + content: | + [Unit] + Description=Docker Application Container Engine + Documentation=https://docs.docker.com + After=network-online.target docker.socket firewalld.service containerd.service time-set.target + Wants=network-online.target containerd.service + Requires=docker.socket + + [Service] + Type=notify + ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock + ExecReload=/bin/kill -s HUP $MAINPID + TimeoutStartSec=0 + RestartSec=2 + Restart=always + StartLimitBurst=3 + StartLimitInterval=60s + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + Delegate=yes + KillMode=process + OOMScoreAdjust=-500 + + [Install] + WantedBy=multi-user.target + - name: restart service + ansible.builtin.systemd: + name: docker.service + state: restarted + enabled: 'yes' + daemon_reload: 'yes' + - name: add docker group + ansible.builtin.group: + name: docker + - name: add user to docker group + ansible.builtin.user: + name: '{{ SELF.os_ssh_user }}' + groups: docker + append: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: delete docker packages + ansible.builtin.apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + - docker-ce-rootless-extras + state: absent + purge: 'true' + autoremove: 'true' + - name: delete docker directories + ansible.builtin.file: + name: '{{ item }}' + state: absent + loop: + - /var/lib/docker + - /var/lib/containerd + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + docker.engine~docker.engine::terraform@remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_version: '>= 0.14.0' + resource: + terraform_data: + docker: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + [Unit] + Description=Docker Application Container Engine + Documentation=https://docs.docker.com + After=network-online.target docker.socket firewalld.service containerd.service time-set.target + Wants=network-online.target containerd.service + Requires=docker.socket + + [Service] + Type=notify + ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock + ExecReload=/bin/kill -s HUP $MAINPID + TimeoutStartSec=0 + RestartSec=2 + Restart=always + StartLimitBurst=3 + StartLimitInterval=60s + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + Delegate=yes + KillMode=process + OOMScoreAdjust=-500 + + [Install] + WantedBy=multi-user.target + destination: /tmp/docker.service + remote-exec: + - inline: + - curl -sSL https://get.docker.com | sudo sh + - sudo groupadd -f docker + - sudo usermod -aG docker {{ SELF.os_ssh_user }} + - sleep 10s + - cat /tmp/docker.service | sudo tee /lib/systemd/system/docker.service + - sudo systemctl daemon-reload + - sudo systemctl restart docker.service + - inline: + - sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras -y + - sudo rm -rf /var/lib/docker + - sudo rm -rf /var/lib/containerd + when: destroy + docker.engine~software.application#apt.package::ansible@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + docker.engine~software.application#apt.package::terraform@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-docker.engine.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-docker.engine.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-docker.engine.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-docker.engine.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-docker.engine.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#apt.package::ansible@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + docker.engine~software.application#apt.package::terraform@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-docker.engine.sh + remote-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#tar.archive::ansible@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + docker.engine~software.application#tar.archive::terraform@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-docker.engine + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-docker.engine {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-docker.engine -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-docker.engine.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-docker.engine.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-docker.engine.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-docker.engine.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-docker.engine.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#tar.archive::ansible@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + docker.engine~software.application#tar.archive::terraform@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-docker.engine + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-docker.engine {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-docker.engine -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-docker.engine.sh + remote-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#zip.archive::ansible@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + docker.engine~software.application#zip.archive::terraform@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-docker.engine + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-docker.engine {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-docker.engine -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-docker.engine.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-docker.engine.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-docker.engine.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-docker.engine.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-docker.engine.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#zip.archive::ansible@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + docker.engine~software.application#zip.archive::terraform@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-docker.engine + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-docker.engine {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-docker.engine -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-docker.engine.sh + remote-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + mysql.dbms~mysql.dbms#dbms.image::ansible@docker.engine->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + application_port: + type: string + default: 3306 + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + env: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password | string }}' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: delete container + community.docker.docker_container: + name: '{{ SELF.dbms_name }}' + state: absent + mysql.dbms~mysql.dbms#dbms.image::compose@docker.engine->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.dbms_name }}' + services: + application: + container_name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + environment: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.dbms_name }}' + services: + application: + container_name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + environment: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + mysql.dbms~mysql.dbms#dbms.image::terraform@docker.engine->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - name: '{{ SELF.dbms_name }}' + image: ${docker_image.image.image_id} + network_mode: host + env: + - MYSQL_ROOT_PASSWORD={{ SELF.dbms_password }} + docker_image: + image: + - name: mysql:{{ ".artifacts::dbms_image::file" | eval }} + mysql.dbms~mysql.dbms#dbms.image::ansible@docker.engine->remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + attributes: + application_address: + type: string + default: 127.0.0.1 + application_port: + type: string + default: 3306 + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: start container + community.docker.docker_container: + name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + env: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password | string }}' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.dbms~mysql.dbms#dbms.image::compose@docker.engine->remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.dbms_name }}' + services: + application: + container_name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + environment: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.dbms_name }}' + services: + application: + container_name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + environment: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + mysql.dbms~mysql.dbms#dbms.image::terraform@docker.engine->remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 + ssh_opts: + - '-i' + - '{{ SELF.os_ssh_key_file }}' + - '-o' + - IdentitiesOnly=yes + - '-o' + - BatchMode=yes + - '-o' + - UserKnownHostsFile=/dev/null + - '-o' + - StrictHostKeyChecking=no + resource: + docker_container: + application: + - name: '{{ SELF.dbms_name }}' + image: ${docker_image.image.image_id} + network_mode: host + env: + - MYSQL_ROOT_PASSWORD={{ SELF.dbms_password }} + docker_image: + image: + - name: mysql:{{ ".artifacts::dbms_image::file" | eval }} + mysql.dbms~mysql.dbms#dbms.image::ansible@gcp.cloudsql: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + dbms_ssl_mode: + type: string + default: Preferred + attributes: + application_port: + type: string + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: create a instance + register: instance_info + google.cloud.gcp_sql_instance: + name: '{{ SELF.dbms_name }}' + database_version: MYSQL_{{ ".artifacts::dbms_image::file" | eval | replace(".", "_") }} + settings: + tier: db-f1-micro + availability_type: REGIONAL + backup_configuration: + binary_log_enabled: true + enabled: true + ip_configuration: + authorized_networks: + - value: 0.0.0.0/0 + region: '{{ SELF.gcp_region }}' + project: '{{ SELF.gcp_project }}' + - name: set root password + google.cloud.gcp_sql_user: + name: root + host: '%' + password: '{{ SELF.dbms_password }}' + instance: '{{ instance_info }}' + project: '{{ SELF.gcp_project }}' + - name: aet attributes + set_fact: + application_address: '{{ instance_info.ipAddresses[0].ipAddress | trim }}' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address }}' + outputs: + application_address: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: Activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: Delete Instance + ansible.builtin.shell: gcloud sql instances delete {{ SELF.dbms_name }} --quiet + args: + executable: /bin/bash + mysql.dbms~mysql.dbms#dbms.image::terraform@gcp.cloudsql: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + dbms_ssl_mode: + type: string + default: Preferred + attributes: + application_port: + type: string + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: ${google_sql_database_instance.dbms.public_ip_address} + resource: + google_sql_database_instance: + dbms: + - database_version: MYSQL_{{ ".artifacts::dbms_image::file" | eval | replace(".", "_") }} + deletion_protection: false + name: '{{ SELF.dbms_name }}' + root_password: '{{ SELF.dbms_password }}' + settings: + - availability_type: REGIONAL + backup_configuration: + - binary_log_enabled: true + enabled: true + ip_configuration: + - authorized_networks: + - name: public + value: 0.0.0.0/0 + ipv4_enabled: true + tier: db-f1-micro + google_sql_user: + user: + - host: '%' + instance: ${google_sql_database_instance.dbms.name} + name: root + password: ${google_sql_database_instance.dbms.root_password} + mysql.dbms~mysql.dbms#dbms.image::ansible@kubernetes.cluster: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: + eval: .::dbms_name + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file + inputs: + playbook: + q: + - name: create deployment + kubernetes.core.k8s: + wait: true + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.dbms_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.dbms_name }}' + template: + metadata: + labels: + app: '{{ SELF.dbms_name }}' + spec: + containers: + - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + name: '{{ SELF.dbms_name }}' + env: + - name: MYSQL_ROOT_PASSWORD + value: '{{ SELF.dbms_password }}' + ports: + - containerPort: 3306 + name: mysql + - name: create service + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.dbms_name }}' + namespace: default + spec: + ports: + - name: mysql + port: 3306 + targetPort: 3306 + selector: + app: '{{ SELF.dbms_name }}' + type: ClusterIP + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file + inputs: + playbook: + q: + - name: delete service + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: Service + name: '{{ SELF.dbms_name }}' + namespace: default + - name: delete deployment + kubernetes.core.k8s: + state: absent + api_version: apps/v1 + kind: Deployment + name: '{{ SELF.dbms_name }}' + namespace: default + mysql.dbms~mysql.dbms#dbms.image::kubernetes@kubernetes.cluster: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: + eval: .::dbms_name + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.dbms.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} + vars: + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.dbms_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.dbms_name }}' + template: + metadata: + labels: + app: '{{ SELF.dbms_name }}' + spec: + containers: + - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + name: '{{ SELF.dbms_name }}' + env: + - name: MYSQL_ROOT_PASSWORD + value: '{{ SELF.dbms_password }}' + ports: + - containerPort: 3306 + name: mysql + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.dbms_name }}' + spec: + ports: + - name: mysql + port: 3306 + targetPort: 3306 + selector: + app: '{{ SELF.dbms_name }}' + type: ClusterIP + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} rollout status deployment/{{ SELF.dbms_name }} --timeout 60s + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.dbms.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} + vars: + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.dbms_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.dbms_name }}' + template: + metadata: + labels: + app: '{{ SELF.dbms_name }}' + spec: + containers: + - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + name: '{{ SELF.dbms_name }}' + env: + - name: MYSQL_ROOT_PASSWORD + value: '{{ SELF.dbms_password }}' + ports: + - containerPort: 3306 + name: mysql + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.dbms_name }}' + spec: + ports: + - name: mysql + port: 3306 + targetPort: 3306 + selector: + app: '{{ SELF.dbms_name }}' + type: ClusterIP + - name: unapply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + mysql.dbms~mysql.dbms#dbms.image::terraform@kubernetes.cluster: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: + eval: .::dbms_name + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - kubernetes: + source: hashicorp/kubernetes + version: 2.31.0 + required_version: '>= 0.14.0' + provider: + kubernetes: + - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} + client_key: ${file("{{ SELF.k8s_client_key_file }}")} + cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} + host: '{{ SELF.k8s_host }}' + resource: + kubernetes_deployment_v1: + application: + - metadata: + - name: '{{ SELF.dbms_name }}' + spec: + - selector: + - match_labels: + app: '{{ SELF.dbms_name }}' + template: + - metadata: + - labels: + app: '{{ SELF.dbms_name }}' + spec: + - container: + - name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + env: + - name: MYSQL_ROOT_PASSWORD + value: '{{ SELF.dbms_password }}' + port: + - container_port: 3306 + name: mysql + kubernetes_service_v1: + application: + - metadata: + - name: '{{ SELF.dbms_name }}' + spec: + - port: + - name: mysql + port: 3306 + target_port: 3306 + selector: + app: '{{ SELF.dbms_name }}' + type: ClusterIP + mysql.dbms~mysql.dbms#dbms.image::ansible@local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_port: + type: string + default: 3001 + application_address: + type: string + default: 127.0.0.1 + attributes: + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: + eval: .::application_port + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: installing mysql + ansible.builtin.apt: + name: + - mysql-server + - mysql-client + - python3-mysqldb + - libmysqlclient-dev + state: present + update_cache: 'yes' + - name: start and enable mysql service + ansible.builtin.systemd: + name: mysql + state: started + enabled: 'yes' + - name: enable passwordless login + ansible.builtin.copy: + dest: '{{ item }}' + content: | + [client] + user=root + password={{ SELF.dbms_password }} + loop: + - /root/.my.cnf + - /home/{{ SELF.os_ssh_user }}/.my.cnf + - name: configure port (e.g., since 3306 is blocked by the provider) + ansible.builtin.lineinfile: + path: /etc/mysql/mysql.conf.d/mysqld.cnf + regexp: ^# port + line: port = {{ SELF.application_port }} + backup: 'yes' + - name: enable remote login + ansible.builtin.lineinfile: + path: /etc/mysql/mysql.conf.d/mysqld.cnf + regexp: ^bind-address + line: bind-address = 0.0.0.0 + backup: 'yes' + - name: restart mysql + ansible.builtin.systemd: + name: mysql + state: restarted + - name: create all root + community.mysql.mysql_user: + name: root + password: '{{ SELF.dbms_password }}' + priv: '*.*:ALL' + host: '%' + state: present + login_host: localhost + login_password: '{{ SELF.dbms_password }}' + login_port: '{{ SELF.application_port }}' + login_user: root + - name: delete localhost root + community.mysql.mysql_user: + name: root + host: localhost + state: absent + login_host: localhost + login_password: '{{ SELF.dbms_password }}' + login_port: '{{ SELF.application_port }}' + login_user: root + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: uninstalling mysql + ansible.builtin.apt: + name: + - mysql-server + - mysql-client + - python3-mysqldb + - libmysqlclient-dev + state: absent + - name: remove passwordless login + ansible.builtin.file: + name: '{{ item }}' + state: absent + loop: + - /root/.my.cnf + - /home/{{ SELF.os_ssh_user }}/.my.cnf + mysql.dbms~mysql.dbms#dbms.image::terraform@local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_port: + type: string + default: 3001 + application_address: + type: string + default: 127.0.0.1 + attributes: + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: + eval: .::application_port + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_script: + content: | + + #!/usr/bin/bash + set -e + export DEBIAN_FRONTEND="noninteractive" + + DBMS_PASSWORD=$1 + DBMS_PORT=$2 + + # Set password + debconf-set-selections <<< "mysql-server mysql-server/root_password password ${DBMS_PASSWORD}" + debconf-set-selections <<< "mysql-server mysql-server/root_password_again password ${DBMS_PASSWORD}" + + # Install mysql + apt-get update -y + apt-get -y install mysql-server + + # Passwordless auth + cat < /root/.my.cnf + [client] + user=root + password=${DBMS_PASSWORD} + EOF + + # Listen on all interfaces + sed -i "s/127\.0\.0\.1/0\.0\.0\.0/g" /etc/mysql/mysql.conf.d/mysqld.cnf + + # Listen on custom port + sed -i "s/# port.*/port = ${DBMS_PORT}/g" /etc/mysql/mysql.conf.d/mysqld.cnf + + # Configure any host for root + mysql -u root -e 'USE mysql; UPDATE user SET host = "%" WHERE user = "root"; FLUSH PRIVILEGES;' + mysql -u root -e 'USE mysql; DELETE FROM user WHERE user = "root" and host = "localhost"; FLUSH PRIVILEGES;' + + # Enable service + systemctl enable mysql + + # Restart service + systemctl restart mysql + filename: /tmp/install-mysql-dbms.sh + terraform_data: + local: + - depends_on: local_file.tmp_script + provisioner: + local-exec: + - inline: + - sudo bash /tmp/install-mysql-dbms.sh {{ SELF.dbms_password }} {{ SELF.application_port }} + mysql.dbms~mysql.dbms#dbms.image::ansible@remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_port: + type: string + default: 3001 + application_address: + type: string + default: 127.0.0.1 + attributes: + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: + eval: .::application_port + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: installing mysql + ansible.builtin.apt: + name: + - mysql-server + - mysql-client + - python3-mysqldb + - libmysqlclient-dev + state: present + update_cache: 'yes' + - name: start and enable mysql service + ansible.builtin.systemd: + name: mysql + state: started + enabled: 'yes' + - name: enable passwordless login + ansible.builtin.copy: + dest: '{{ item }}' + content: | + [client] + user=root + password={{ SELF.dbms_password }} + loop: + - /root/.my.cnf + - /home/{{ SELF.os_ssh_user }}/.my.cnf + - name: configure port (e.g., since 3306 is blocked by the provider) + ansible.builtin.lineinfile: + path: /etc/mysql/mysql.conf.d/mysqld.cnf + regexp: ^# port + line: port = {{ SELF.application_port }} + backup: 'yes' + - name: enable remote login + ansible.builtin.lineinfile: + path: /etc/mysql/mysql.conf.d/mysqld.cnf + regexp: ^bind-address + line: bind-address = 0.0.0.0 + backup: 'yes' + - name: restart mysql + ansible.builtin.systemd: + name: mysql + state: restarted + - name: create all root + community.mysql.mysql_user: + name: root + password: '{{ SELF.dbms_password }}' + priv: '*.*:ALL' + host: '%' + state: present + login_host: localhost + login_password: '{{ SELF.dbms_password }}' + login_port: '{{ SELF.application_port }}' + login_user: root + - name: delete localhost root + community.mysql.mysql_user: + name: root + host: localhost + state: absent + login_host: localhost + login_password: '{{ SELF.dbms_password }}' + login_port: '{{ SELF.application_port }}' + login_user: root + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: uninstalling mysql + ansible.builtin.apt: + name: + - mysql-server + - mysql-client + - python3-mysqldb + - libmysqlclient-dev + state: absent + - name: remove passwordless login + ansible.builtin.file: + name: '{{ item }}' + state: absent + loop: + - /root/.my.cnf + - /home/{{ SELF.os_ssh_user }}/.my.cnf + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.dbms~mysql.dbms#dbms.image::terraform@remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_port: + type: string + default: 3001 + application_address: + type: string + default: 127.0.0.1 + attributes: + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: + eval: .::application_port + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + + #!/usr/bin/bash + set -e + export DEBIAN_FRONTEND="noninteractive" + + DBMS_PASSWORD=$1 + DBMS_PORT=$2 + + # Set password + debconf-set-selections <<< "mysql-server mysql-server/root_password password ${DBMS_PASSWORD}" + debconf-set-selections <<< "mysql-server mysql-server/root_password_again password ${DBMS_PASSWORD}" + + # Install mysql + apt-get update -y + apt-get -y install mysql-server + + # Passwordless auth + cat < /root/.my.cnf + [client] + user=root + password=${DBMS_PASSWORD} + EOF + + # Listen on all interfaces + sed -i "s/127\.0\.0\.1/0\.0\.0\.0/g" /etc/mysql/mysql.conf.d/mysqld.cnf + + # Listen on custom port + sed -i "s/# port.*/port = ${DBMS_PORT}/g" /etc/mysql/mysql.conf.d/mysqld.cnf + + # Configure any host for root + mysql -u root -e 'USE mysql; UPDATE user SET host = "%" WHERE user = "root"; FLUSH PRIVILEGES;' + mysql -u root -e 'USE mysql; DELETE FROM user WHERE user = "root" and host = "localhost"; FLUSH PRIVILEGES;' + + # Enable service + systemctl enable mysql + + # Restart service + systemctl restart mysql + destination: /tmp/install-mysql-dbms.sh + remote-exec: + - inline: + - sudo bash /tmp/install-mysql-dbms.sh {{ SELF.dbms_password }} {{ SELF.application_port }} + mysql.dbms~software.application#apt.package::ansible@*->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + mysql.dbms~software.application#apt.package::terraform@*->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-mysql.dbms.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-mysql.dbms.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-mysql.dbms.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-mysql.dbms.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-mysql.dbms.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.dbms~software.application#apt.package::ansible@*->remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.dbms~software.application#apt.package::terraform@*->remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-mysql.dbms.sh + remote-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.dbms~software.application#tar.archive::ansible@*->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + mysql.dbms~software.application#tar.archive::terraform@*->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-mysql.dbms + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-mysql.dbms -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-mysql.dbms.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-mysql.dbms.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-mysql.dbms.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-mysql.dbms.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-mysql.dbms.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.dbms~software.application#tar.archive::ansible@*->remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.dbms~software.application#tar.archive::terraform@*->remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-mysql.dbms + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-mysql.dbms -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-mysql.dbms.sh + remote-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.dbms~software.application#zip.archive::ansible@*->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + mysql.dbms~software.application#zip.archive::terraform@*->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-mysql.dbms + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-mysql.dbms -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-mysql.dbms.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-mysql.dbms.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-mysql.dbms.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-mysql.dbms.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-mysql.dbms.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.dbms~software.application#zip.archive::ansible@*->remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.dbms~software.application#zip.archive::terraform@*->remote.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-mysql.dbms + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-mysql.dbms -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-mysql.dbms.sh + remote-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.database~mysql.database::ansible@mysql.dbms->docker.engine->local.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: get dbms container info + community.docker.docker_container_info: + name: '{{ HOST.dbms_name }}' + register: dbms_container_info + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: delete user (with privileges) + community.mysql.mysql_user: + state: absent + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: delete database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + state: absent + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + mysql.database~mysql.database::compose@mysql.dbms->docker.engine->local.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + services: + job: + container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + services: + job: + container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + mysql.database~mysql.database::terraform@mysql.dbms->docker.engine->local.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - mysql: + source: petoju/mysql + version: 3.0.48 + provider: + mysql: + - endpoint: 127.0.0.1:{{ HOST.management_port }} + password: '{{ HOST.dbms_password }}' + username: root + resource: + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + mysql.database~mysql.database::ansible@mysql.dbms->docker.engine->remote.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install pip + ansible.builtin.apt: + name: python3-pip + state: present + - name: install pymysql + ansible.builtin.pip: + name: pymysql + state: present + - name: get dbms container info + community.docker.docker_container_info: + name: '{{ HOST.dbms_name }}' + register: dbms_container_info + - name: forward port + when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" + community.docker.docker_container: + name: '{{ HOST.dbms_name }}-port-forward' + image: nicolaka/netshoot:v0.13 + command: socat TCP6-LISTEN:3306,fork TCP:{{ HOST.dbms_name }}:3306 + ports: + - '{{ HOST.application_port }}:3306' + - name: create forwarding network + community.docker.docker_network: + name: '{{ HOST.dbms_name }}-port-forward' + connected: + - '{{ HOST.dbms_name }}-port-forward' + - '{{ HOST.dbms_name }}' + when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: unforward port + when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" + community.docker.docker_container: + name: '{{ HOST.dbms_name }}-port-forward' + state: absent + - name: remove forwarding network + community.docker.docker_network: + name: '{{ HOST.dbms_name }}-port-forward' + state: absent + when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: delete user (with privileges) + community.mysql.mysql_user: + state: absent + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: delete database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + state: absent + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.database~mysql.database::compose@mysql.dbms->docker.engine->remote.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + services: + job: + container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + services: + job: + container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + mysql.database~mysql.database::terraform@mysql.dbms->docker.engine->remote.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - mysql: + source: petoju/mysql + version: 3.0.48 + ssh: + source: AndrewChubatiuk/ssh + version: 0.2.3 + data: + ssh_tunnel: + mysql: + - remote: + host: '{{ HOST.application_address }}' + port: '{{ HOST.application_port }}' + provider: + mysql: + - endpoint: ${data.ssh_tunnel.mysql.local.address} + password: '{{ HOST.dbms_password }}' + username: root + ssh: + - auth: + private_key: + content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} + server: + host: '{{ HOST.management_address }}' + port: 22 + user: '{{ SELF.os_ssh_user }}' + resource: + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + mysql.database~mysql.database::ansible@mysql.dbms->gcp.cloudsql: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: create a database + google.cloud.gcp_sql_database: + name: '{{ SELF.database_name }}' + charset: utf8 + instance: '{{ HOST.dbms_name }}' + project: '{{ SELF.gcp_project }}' + - name: install GCP CloudSQL Proxy + ansible.builtin.get_url: + url: https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.13.0/cloud-sql-proxy.linux.amd64 + dest: /tmp/gcp-cloudsql-proxy + mode: '0755' + - name: forward port + ansible.builtin.shell: '/tmp/gcp-cloudsql-proxy {{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }} --credentials-file {{ SELF.gcp_service_account_file }} --port 23306 ' + args: + executable: /usr/bin/bash + async: 30 + poll: 0 + - name: wait for port + ansible.builtin.wait_for: + host: 127.0.0.1 + port: 23306 + delay: 5 + timeout: 30 + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: 127.0.0.1 + login_password: '{{ HOST.dbms_password }}' + login_port: 23306 + login_user: root + - name: unforward port + ansible.builtin.shell: pkill -f "/tmp/gcp-cloudsql-proxy {{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }}" + args: + executable: /usr/bin/bash + mysql.database~mysql.database::terraform@mysql.dbms->gcp.cloudsql: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + environment: + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file + delete: + implementation: + primary: Terraform + environment: + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + mysql: + source: petoju/mysql + version: 3.0.48 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + mysql: + - endpoint: cloudsql://{{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }} + password: '{{ HOST.dbms_password }}' + username: root + resource: + google_sql_database: + database: + - name: '{{ SELF.database_name }}' + instance: '{{ HOST.dbms_name }}' + google_sql_user: + user: + - host: '%' + instance: '{{ HOST.dbms_name }}' + name: '{{ SELF.database_name }}' + password: '{{ SELF.database_password }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${google_sql_user.user.name} + mysql.database~mysql.database::ansible@mysql.dbms->kubernetes.cluster: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: deploy database + block: + - name: forward port + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.dbms_name }} 23306:3306 + args: + executable: /usr/bin/bash + async: 30 + poll: 0 + - name: wait for port + ansible.builtin.wait_for: + host: 127.0.0.1 + port: 23306 + delay: 5 + timeout: 30 + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: 127.0.0.1 + login_password: '{{ HOST.dbms_password }}' + login_port: '23306' + login_user: root + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: 127.0.0.1 + login_password: '{{ HOST.dbms_password }}' + login_port: '23306' + login_user: root + always: + - name: unforward port + ansible.builtin.shell: pkill -f "port-forward service/{{ HOST.dbms_name }}" + args: + executable: /usr/bin/bash + mysql.database~mysql.database::kubernetes@mysql.dbms->kubernetes.cluster: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: '{{ job | to_yaml }}' + vars: + job: + apiVersion: batch/v1 + kind: Job + metadata: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' + spec: + template: + spec: + restartPolicy: Never + containers: + - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.database_name }}-{{ HOST.dbms_name }} + args: + executable: /usr/bin/bash + - name: cleanup + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: '{{ job | to_yaml }}' + vars: + job: + apiVersion: batch/v1 + kind: Job + metadata: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' + spec: + template: + spec: + restartPolicy: Never + containers: + - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.database_name }}-{{ HOST.dbms_name }} + args: + executable: /usr/bin/bash + - name: cleanup + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + mysql.database~mysql.database::terraform@mysql.dbms->kubernetes.cluster: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - mysql: + source: petoju/mysql + version: 3.0.48 + provider: + mysql: + - endpoint: ${terraform_data.forward_port.input} + password: '{{ HOST.dbms_password }}' + username: root + resource: + terraform_data: + forward_port: + - input: 127.0.0.1:23306 + provisioner: + local-exec: + command: |- + (nohup kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.dbms_name }} 23306:3306 > /dev/null 2>&1 &) + sleep 5s + interpreter: + - /bin/bash + - '-c' + unforward_port: + - depends_on: + - mysql_grant.user + provisioner: + local-exec: + command: pkill -f "port-forward service/{{ HOST.dbms_name }}" + interpreter: + - /bin/bash + - '-c' + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + mysql.database~mysql.database::ansible@mysql.dbms->local.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install pip + ansible.builtin.apt: + name: python3-pip + state: present + - name: install pymysql + ansible.builtin.pip: + name: pymysql + state: present + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: delete user (with privileges) + community.mysql.mysql_user: + state: absent + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: delete database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + state: absent + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + mysql.database~mysql.database::terraform@mysql.dbms->local.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - mysql: + source: petoju/mysql + version: 3.0.48 + provider: + mysql: + - endpoint: '{{ HOST.application_address }}:{{ HOST.application_port }}' + password: '{{ HOST.dbms_password }}' + username: root + resource: + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + mysql.database~mysql.database::ansible@mysql.dbms->remote.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install pip + ansible.builtin.apt: + name: python3-pip + state: present + - name: install pymysql + ansible.builtin.pip: + name: pymysql + state: present + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: delete user (with privileges) + community.mysql.mysql_user: + state: absent + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: delete database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + state: absent + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.database~mysql.database::terraform@mysql.dbms->remote.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - mysql: + source: petoju/mysql + version: 3.0.48 + ssh: + source: AndrewChubatiuk/ssh + version: 0.2.3 + data: + ssh_tunnel: + mysql: + - remote: + host: '{{ HOST.application_address }}' + port: '{{ HOST.application_port }}' + provider: + mysql: + - endpoint: ${data.ssh_tunnel.mysql.local.address} + password: '{{ HOST.dbms_password }}' + username: root + ssh: + - auth: + private_key: + content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} + server: + host: '{{ HOST.management_address }}' + port: 22 + user: '{{ SELF.os_ssh_user }}' + resource: + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + minio.server~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + minio.server~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + minio.server~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - MINIO_ROOT_USER={{ SELF.access_key }} + - MINIO_ROOT_PASSWORD={{ SELF.secret_key }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' + minio.server~service.application#docker.image::ansible@docker.engine->remote.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + minio.server~service.application#docker.image::compose@docker.engine->remote.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + minio.server~service.application#docker.image::terraform@docker.engine->remote.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + provider: + docker: + - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 + ssh_opts: + - '-i' + - '{{ SELF.os_ssh_key_file }}' + - '-o' + - IdentitiesOnly=yes + - '-o' + - BatchMode=yes + - '-o' + - UserKnownHostsFile=/dev/null + - '-o' + - StrictHostKeyChecking=no + resource: + docker_container: + application: + - env: + - MINIO_ROOT_USER={{ SELF.access_key }} + - MINIO_ROOT_PASSWORD={{ SELF.secret_key }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' + minio.server~service.application#docker.image::ansible@gcp.cloudrun: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: touch service + register: service + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.service.yaml' + - name: create service + ansible.builtin.copy: + dest: '{{ service.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + apiVersion: serving.knative.dev/v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + labels: + cloud.googleapis.com/location: '{{ SELF.gcp_region }}' + annotations: + run.googleapis.com/ingress: all + spec: + template: + spec: + containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + ports: + - name: http1 + containerPort: '{{ SELF.application_port }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + - name: apply service + ansible.builtin.shell: gcloud run services replace {{ service.path }} --quiet + args: + executable: /bin/bash + - name: touch policy + register: policy + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.policy.yaml' + - name: fill policy + ansible.builtin.copy: + dest: '{{ policy.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + bindings: + - members: + - allUsers + role: roles/run.invoker + - name: apply policy + ansible.builtin.shell: gcloud run services set-iam-policy {{ SELF.application_name }} {{ policy.path }} --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + - name: describe service + register: service_description + ansible.builtin.shell: gcloud run services describe {{ SELF.application_name }} --region {{ SELF.gcp_region }} --quiet --format=json + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ (service_description.stdout | from_json ).status.url[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ (service_description.stdout | from_json ).status.url[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address | trim }}' + application_endpoint: '{{ outputs.application_endpoint | trim }}' + outputs: + application_address: + application_endpoint: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud run services delete {{ SELF.application_name }} --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + minio.server~service.application#docker.image::terraform@gcp.cloudrun: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: ${substr(google_cloud_run_v2_service.application.uri, 8, -1)} + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://${substr(google_cloud_run_v2_service.application.uri, 8, -1)}:443' + resource: + google_cloud_run_v2_service: + application: + - ingress: INGRESS_TRAFFIC_ALL + location: '{{ SELF.gcp_region }}' + name: '{{ SELF.application_name }}' + template: + - containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + ports: + - name: http1 + container_port: '{{ SELF.application_port }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + google_cloud_run_service_iam_binding: + application: + - location: '{{ SELF.gcp_region }}' + members: + - allUsers + role: roles/run.invoker + service: '{{ SELF.application_name }}' + minio.server~service.application#docker.image::ansible@kubernetes.cluster: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: + eval: .::application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file + inputs: + playbook: + q: + - name: create deployment + kubernetes.core.k8s: + wait: true + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.application_name }}' + template: + metadata: + labels: + app: '{{ SELF.application_name }}' + spec: + containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + name: '{{ SELF.application_name }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + ports: + - containerPort: '{{ SELF.application_port }}' + - name: create service + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file + inputs: + playbook: + q: + - name: delete service + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: Service + namespace: default + name: '{{ SELF.application_name }}' + - name: delete deployment + kubernetes.core.k8s: + state: absent + api_version: app/v1 + kind: Deployment + namespace: default + name: '{{ SELF.application_name }}' + minio.server~service.application#docker.image::kubernetes@kubernetes.cluster: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: + eval: .::application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.application.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} + vars: + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.application_name }}' + template: + metadata: + labels: + app: '{{ SELF.application_name }}' + spec: + containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + name: '{{ SELF.application_name }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + ports: + - containerPort: '{{ SELF.application_port }}' + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} rollout status deployment/{{ SELF.application_name }} --timeout 60s + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.application.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} + vars: + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.application_name }}' + template: + metadata: + labels: + app: '{{ SELF.application_name }}' + spec: + containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + name: '{{ SELF.application_name }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + ports: + - containerPort: '{{ SELF.application_port }}' + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP + - name: unapply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + minio.server~service.application#docker.image::terraform@kubernetes.cluster: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: + eval: .::application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - kubernetes: + source: hashicorp/kubernetes + version: 2.31.0 + required_version: '>= 0.14.0' + provider: + kubernetes: + - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} + client_key: ${file("{{ SELF.k8s_client_key_file }}")} + cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} + host: '{{ SELF.k8s_host }}' + resource: + kubernetes_deployment_v1: + application: + - metadata: + - name: '{{ SELF.application_name }}' + spec: + - selector: + - match_labels: + app: '{{ SELF.application_name }}' + template: + - metadata: + - labels: + app: '{{ SELF.application_name }}' + spec: + - container: + - env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + image: '{{ ".artifacts::docker_image::file" | eval }}' + name: '{{ SELF.application_name }}' + port: + - container_port: '{{ SELF.application_port }}' + kubernetes_service_v1: + application: + - metadata: + - name: '{{ SELF.application_name }}' + spec: + - port: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + target_port: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP + minio.server~service.application#tar.archive::ansible@*->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + minio.server~service.application#tar.archive::terraform@*->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-minio.server.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~service.application#tar.archive::ansible@*->remote.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + minio.server~service.application#tar.archive::terraform@*->remote.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-minio.server.sh + remote-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~service.application#zip.archive::ansible@*->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + minio.server~service.application#zip.archive::terraform@*->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string default: - get_input: gcp_service_account_file - gcp_region: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-minio.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-minio.server.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~service.application#zip.archive::ansible@*->remote.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_project + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.appengine~gcp.service::terraform: - derived_from: gcp.appengine + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + minio.server~service.application#zip.archive::terraform@*->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + os_ssh_host: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -5580,24 +20518,158 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.appenginereporting~gcp.service::ansible: - derived_from: gcp.appenginereporting + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-minio.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-minio.server.sh + remote-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~service.application#zip.archive::ansible@gcp.appengine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -5621,103 +20693,79 @@ node_types: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.appenginereporting~gcp.service::terraform: - derived_from: gcp.appenginereporting - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory + ansible.builtin.tempfile: + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + args: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address | trim }}' + application_endpoint: '{{ outputs.application_endpoint | trim }}' + outputs: + application_address: + application_endpoint: delete: - implementation: - primary: Terraform - defaults: - inputs: - main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.cloudbuild~gcp.service::ansible: - derived_from: gcp.cloudbuild - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project - interfaces: - Standard: - operations: - create: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.cloudbuild~gcp.service::terraform: - derived_from: gcp.cloudbuild + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + minio.server~service.application#zip.archive::terraform@gcp.appengine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -5744,159 +20792,259 @@ node_types: implementation: primary: Terraform defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint inputs: main: terraform: - required_providers: - google: source: hashicorp/google - version: 4.67.0 + version: 5.39.1 provider: google: - credentials: '{{ SELF.gcp_service_account_file }}' project: '{{ SELF.gcp_project }}' region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - docker.engine~docker.engine::ansible@remote.machine: - derived_from: docker.engine + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + minio.server~software.application#apt.package::ansible@*->local.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: + application_directory: type: string default: - get_input: os_ssh_key_file + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: install docker - ansible.builtin.shell: curl -sSL https://get.docker.com | sh + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh args: - executable: /usr/bin/bash - - name: update service + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: /lib/systemd/system/docker.service - content: | - [Unit] - Description=Docker Application Container Engine - Documentation=https://docs.docker.com - After=network-online.target docker.socket firewalld.service containerd.service time-set.target - Wants=network-online.target containerd.service - Requires=docker.socket + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e - [Service] - Type=notify - ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock - ExecReload=/bin/kill -s HUP $MAINPID - TimeoutStartSec=0 - RestartSec=2 - Restart=always - StartLimitBurst=3 - StartLimitInterval=60s - LimitNPROC=infinity - LimitCORE=infinity - TasksMax=infinity - Delegate=yes - KillMode=process - OOMScoreAdjust=-500 + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e - [Install] - WantedBy=multi-user.target - - name: restart service - ansible.builtin.systemd: - name: docker.service - state: restarted - enabled: 'yes' - daemon_reload: 'yes' - - name: add docker group - ansible.builtin.group: - name: docker - - name: add user to docker group - ansible.builtin.user: - name: '{{ SELF.os_ssh_user }}' - groups: docker - append: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: delete docker packages - ansible.builtin.apt: - name: - - docker-ce - - docker-ce-cli - - containerd.io - - docker-buildx-plugin - - docker-compose-plugin - - docker-ce-rootless-extras - state: absent - purge: 'true' - autoremove: 'true' - - name: delete docker directories + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory ansible.builtin.file: - name: '{{ item }}' + path: '{{ SELF.application_directory }}' state: absent - loop: - - /var/lib/docker - - /var/lib/containerd - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - docker.engine~docker.engine::terraform@remote.machine: - derived_from: docker.engine + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + minio.server~software.application#apt.package::terraform@*->local.machine: + derived_from: minio.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: + application_directory: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - attributes: - application_address: - type: string - default: 127.0.0.1 + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -5910,79 +21058,167 @@ node_types: inputs: main: resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-minio.server.sh terraform_data: - docker: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - content: | - [Unit] - Description=Docker Application Container Engine - Documentation=https://docs.docker.com - After=network-online.target docker.socket firewalld.service containerd.service time-set.target - Wants=network-online.target containerd.service - Requires=docker.socket - - [Service] - Type=notify - # the default is not to use systemd for cgroups because the delegate issues still - # exists and systemd currently does not support the cgroup feature set required - # for containers run by docker - ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock - ExecReload=/bin/kill -s HUP $MAINPID - TimeoutStartSec=0 - RestartSec=2 - Restart=always - - # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229. - # Both the old, and new location are accepted by systemd 229 and up, so using the old location - # to make them work for either version of systemd. - StartLimitBurst=3 - - # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230. - # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make - # this option work for either version of systemd. - StartLimitInterval=60s - - # Having non-zero Limit*s causes performance problems due to accounting overhead - # in the kernel. We recommend using cgroups to do container-local accounting. - LimitNPROC=infinity - LimitCORE=infinity - - # Comment TasksMax if your systemd version does not support it. - # Only systemd 226 and above support this option. - TasksMax=infinity - - # set delegate yes so that systemd does not reset the cgroups of docker containers - Delegate=yes - - # kill only the docker process, not all processes in the cgroup - KillMode=process - OOMScoreAdjust=-500 - - [Install] - WantedBy=multi-user.target - destination: /tmp/docker.service - remote-exec: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: - inline: - - curl -sSL https://get.docker.com | sudo sh - - sudo groupadd -f docker - - sudo usermod -aG docker {{ SELF.os_ssh_user }} - - sleep 10s - - cat /tmp/docker.service | sudo tee /lib/systemd/system/docker.service - - sudo systemctl daemon-reload - - sudo systemctl restart docker.service + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh - inline: - - sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras -y - - sudo rm -rf /var/lib/docker - - sudo rm -rf /var/lib/containerd + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh when: destroy - docker.engine~software.application#apt.package::ansible@*->remote.machine: - derived_from: docker.engine + minio.server~software.application#apt.package::ansible@*->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -6113,6 +21349,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -6144,6 +21384,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -6203,8 +21447,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - docker.engine~software.application#apt.archive::terraform@*->remote.machine: - derived_from: docker.engine + minio.server~software.application#apt.package::terraform@*->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' properties: @@ -6285,18 +21529,10 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-docker.engine {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -6313,7 +21549,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-docker.engine.sh + destination: /tmp/create-minio.server.sh - content: | #!/usr/bin/bash set -e @@ -6331,7 +21567,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-docker.engine.sh + destination: /tmp/configure-minio.server.sh - content: | #!/usr/bin/bash set -e @@ -6349,7 +21585,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-docker.engine.sh + destination: /tmp/start-minio.server.sh - content: | #!/usr/bin/bash set -e @@ -6367,7 +21603,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-docker.engine.sh + destination: /tmp/stop-minio.server.sh - content: | #!/usr/bin/bash set -e @@ -6391,30 +21627,22 @@ node_types: # Uninstall package apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-docker.engine.sh + destination: /tmp/delete-minio.server.sh remote-exec: - inline: - - sudo bash /tmp/create-docker.engine.sh - - sudo bash /tmp/configure-docker.engine.sh - - sudo bash /tmp/start-docker.engine.sh + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh - inline: - - sudo bash /tmp/stop-docker.engine.sh - - sudo bash /tmp/delete-docker.engine.sh + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh when: destroy - docker.engine~software.application#tar.archive::ansible@*->remote.machine: - derived_from: docker.engine + minio.server~software.application#tar.archive::ansible@*->local.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -6429,14 +21657,16 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - name: wait for ssh wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -6462,8 +21692,8 @@ node_types: ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' content: |- - APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -6480,16 +21710,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -6511,16 +21735,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -6546,16 +21764,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -6581,16 +21793,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -6609,203 +21815,195 @@ node_types: - name: call management operation ansible.builtin.shell: . .env && . .vintner/delete.sh args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - docker.engine~software.application#tar.archive::terraform@*->remote.machine: - derived_from: docker.engine - metadata: - vintner_generated: 'true' - properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - application_directory: - type: string - default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform - delete: - implementation: - primary: Terraform - defaults: - inputs: - main: - resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-docker.engine - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-docker.engine {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-docker.engine -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-docker.engine.sh - remote-exec: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + minio.server~software.application#tar.archive::terraform@*->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-minio.server.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - - sudo bash /tmp/create-docker.engine.sh - - sudo bash /tmp/configure-docker.engine.sh - - sudo bash /tmp/start-docker.engine.sh + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh - inline: - - sudo bash /tmp/stop-docker.engine.sh - - sudo bash /tmp/delete-docker.engine.sh + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh when: destroy - docker.engine~software.application#zip.archive::ansible@*->remote.machine: - derived_from: docker.engine + minio.server~software.application#tar.archive::ansible@*->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -6840,26 +22038,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -6868,8 +22063,8 @@ node_types: ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' content: |- - APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -7026,8 +22221,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - docker.engine~software.application#zip.archive::terraform@*->remote.machine: - derived_from: docker.engine + minio.server~software.application#tar.archive::terraform@*->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' properties: @@ -7073,9 +22268,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-docker.engine - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e @@ -7085,17 +22280,17 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-docker.engine {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-docker.engine -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -7113,7 +22308,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-docker.engine.sh + destination: /tmp/create-minio.server.sh - content: | #!/usr/bin/bash set -e @@ -7131,7 +22326,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-docker.engine.sh + destination: /tmp/configure-minio.server.sh - content: | #!/usr/bin/bash set -e @@ -7155,7 +22350,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-docker.engine.sh + destination: /tmp/start-minio.server.sh - content: | #!/usr/bin/bash set -e @@ -7179,7 +22374,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-docker.engine.sh + destination: /tmp/stop-minio.server.sh - content: | #!/usr/bin/bash set -e @@ -7200,156 +22395,164 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-docker.engine.sh + destination: /tmp/delete-minio.server.sh remote-exec: - inline: - - sudo bash /tmp/create-docker.engine.sh - - sudo bash /tmp/configure-docker.engine.sh - - sudo bash /tmp/start-docker.engine.sh + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh - inline: - - sudo bash /tmp/stop-docker.engine.sh - - sudo bash /tmp/delete-docker.engine.sh + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh when: destroy - mysql.dbms~mysql.dbms#dbms.image::ansible@docker.engine->remote.machine: - derived_from: mysql.dbms + minio.server~software.application#zip.archive::ansible@*->local.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - attributes: - application_address: - type: string - default: 127.0.0.1 - application_port: - type: string - default: 3306 - management_address: + application_directory: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: 3306 + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: start container - community.docker.docker_container: - name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - network_mode: host - env: - MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password | string }}' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - delete: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: delete container - community.docker.docker_container: - name: '{{ SELF.dbms_name }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~mysql.dbms#dbms.image::compose@docker.engine->remote.machine: - derived_from: mysql.dbms - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - attributes: - application_address: - type: string - default: 127.0.0.1 - application_port: - type: integer - default: 3306 - management_address: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: 3306 - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address - interfaces: - Standard: - operations: - create: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.compose.yaml' - - name: create compose + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.dbms_name }}' - services: - application: - container_name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - network_mode: host - environment: - MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - - name: let it cook - ansible.builtin.pause: - seconds: 10 + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" delete: implementation: primary: Ansible @@ -7357,69 +22560,39 @@ node_types: inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.compose.yaml' - - name: create compose + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.dbms_name }}' - services: - application: - container_name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - network_mode: host - environment: - MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - mysql.dbms~mysql.dbms#dbms.image::terraform@docker.engine->remote.machine: - derived_from: mysql.dbms + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + minio.server~software.application#zip.archive::terraform@*->local.machine: + derived_from: minio.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - attributes: - application_address: - type: string - default: 127.0.0.1 - application_port: - type: integer - default: 3306 - management_address: + application_directory: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: 3306 - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -7432,252 +22605,577 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - docker: - source: kreuzwerker/docker - version: 3.0.2 - provider: - docker: - - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 - ssh_opts: - - '-i' - - '{{ SELF.os_ssh_key_file }}' - - '-o' - - IdentitiesOnly=yes - - '-o' - - BatchMode=yes - - '-o' - - UserKnownHostsFile=/dev/null - - '-o' - - StrictHostKeyChecking=no resource: - docker_container: - application: - - name: '{{ SELF.dbms_name }}' - image: ${docker_image.image.image_id} - network_mode: host - env: - - MYSQL_ROOT_PASSWORD={{ SELF.dbms_password }} - docker_image: - image: - - name: mysql:{{ ".artifacts::dbms_image::file" | eval }} - mysql.dbms~mysql.dbms#dbms.image::ansible@gcp.cloudsql: - derived_from: mysql.dbms + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-minio.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-minio.server.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~software.application#zip.archive::ansible@*->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: + os_ssh_user: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_project - dbms_ssl_mode: - type: string - default: Preferred - attributes: - application_port: - type: string - default: 3306 - management_address: + get_input: os_ssh_key_file + application_directory: type: string default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: create a instance - register: instance_info - google.cloud.gcp_sql_instance: - name: '{{ SELF.dbms_name }}' - database_version: MYSQL_{{ ".artifacts::dbms_image::file" | eval | replace(".", "_") }} - settings: - tier: db-f1-micro - availability_type: REGIONAL - backup_configuration: - binary_log_enabled: true - enabled: true - ip_configuration: - authorized_networks: - - value: 0.0.0.0/0 - region: '{{ SELF.gcp_region }}' - project: '{{ SELF.gcp_project }}' - - name: set root password - google.cloud.gcp_sql_user: - name: root - host: '%' - password: '{{ SELF.dbms_password }}' - instance: '{{ instance_info }}' - project: '{{ SELF.gcp_project }}' - - name: aet attributes - set_fact: - application_address: '{{ instance_info.ipAddresses[0].ipAddress | trim }}' - resultTemplate: | - name: SELF - attributes: - application_address: '{{ outputs.application_address }}' - outputs: - application_address: - delete: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: Activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: Delete Instance - ansible.builtin.shell: gcloud sql instances delete {{ SELF.dbms_name }} --quiet + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - mysql.dbms~mysql.dbms#dbms.image::terraform@gcp.cloudsql: - derived_from: mysql.dbms - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project - dbms_ssl_mode: - type: string - default: Preferred - attributes: - application_port: - type: string - default: 3306 - management_address: - type: string - default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' delete: implementation: - primary: Terraform - defaults: - outputs: - application_address: application_address - inputs: - main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: ${google_sql_database_instance.dbms.public_ip_address} - resource: - google_sql_database_instance: - dbms: - - database_version: MYSQL_{{ ".artifacts::dbms_image::file" | eval | replace(".", "_") }} - deletion_protection: false - name: '{{ SELF.dbms_name }}' - root_password: '{{ SELF.dbms_password }}' - settings: - - availability_type: REGIONAL - backup_configuration: - - binary_log_enabled: true - enabled: true - ip_configuration: - - authorized_networks: - - name: public - value: 0.0.0.0/0 - ipv4_enabled: true - tier: db-f1-micro - google_sql_user: - user: - - host: '%' - instance: ${google_sql_database_instance.dbms.name} - name: root - password: ${google_sql_database_instance.dbms.root_password} - mysql.dbms~mysql.dbms#dbms.image::ansible@kubernetes.cluster: - derived_from: mysql.dbms + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + minio.server~software.application#zip.archive::terraform@*->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - k8s_host: + os_ssh_user: type: string default: - get_input: k8s_host - k8s_ca_cert_file: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: + get_input: os_ssh_key_file + os_ssh_host: type: string default: - get_input: k8s_client_cert_file - k8s_client_key_file: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: type: string default: - get_input: k8s_client_key_file + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-minio.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-minio.server.sh + remote-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + redis.server~redis.server#cache.image::ansible@docker.engine->local.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl attributes: application_address: type: string - default: - eval: .::dbms_name - application_port: - type: integer - default: 3306 - management_address: - type: string - default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port + default: 127.0.0.1 interfaces: Standard: operations: @@ -7685,129 +23183,39 @@ node_types: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - K8S_AUTH_HOST: - eval: .::k8s_host - K8S_AUTH_SSL_CA_CERT: - eval: .::k8s_ca_cert_file - K8S_AUTH_CERT_FILE: - eval: .::k8s_client_cert_file - K8S_AUTH_KEY_FILE: - eval: .::k8s_client_key_file inputs: playbook: q: - - name: create deployment - kubernetes.core.k8s: - wait: true - definition: - apiVersion: apps/v1 - kind: Deployment - metadata: - name: '{{ SELF.dbms_name }}' - namespace: default - spec: - selector: - matchLabels: - app: '{{ SELF.dbms_name }}' - template: - metadata: - labels: - app: '{{ SELF.dbms_name }}' - spec: - containers: - - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - name: '{{ SELF.dbms_name }}' - env: - - name: MYSQL_ROOT_PASSWORD - value: '{{ SELF.dbms_password }}' - ports: - - containerPort: 3306 - name: mysql - - name: create service - kubernetes.core.k8s: - definition: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.dbms_name }}' - namespace: default - spec: - ports: - - name: mysql - port: 3306 - targetPort: 3306 - selector: - app: '{{ SELF.dbms_name }}' - type: ClusterIP + - name: start container + community.docker.docker_container: + name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: redis --port {{ SELF.application_port }} + env: + APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' + APPLICATION_NAME: '"{{ SELF.application_name }}"' + APPLICATION_PORT: '"{{ SELF.application_port }}"' delete: implementation: - primary: Ansible - operation_host: ORCHESTRATOR - environment: - K8S_AUTH_HOST: - eval: .::k8s_host - K8S_AUTH_SSL_CA_CERT: - eval: .::k8s_ca_cert_file - K8S_AUTH_CERT_FILE: - eval: .::k8s_client_cert_file - K8S_AUTH_KEY_FILE: - eval: .::k8s_client_key_file - inputs: - playbook: - q: - - name: delete service - kubernetes.core.k8s: - state: absent - api_version: v1 - kind: Service - name: '{{ SELF.dbms_name }}' - namespace: default - - name: delete deployment - kubernetes.core.k8s: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.cache_name }}' state: absent - api_version: apps/v1 - kind: Deployment - name: '{{ SELF.dbms_name }}' - namespace: default - mysql.dbms~mysql.dbms#dbms.image::kubernetes@kubernetes.cluster: - derived_from: mysql.dbms + redis.server~redis.server#cache.image::compose@docker.engine->local.machine: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: - type: string - default: - get_input: k8s_client_key_file attributes: application_address: type: string - default: - eval: .::dbms_name - application_port: - type: integer - default: 3306 - management_address: - type: string - default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port + default: 127.0.0.1 interfaces: Standard: operations: @@ -7818,66 +23226,34 @@ node_types: inputs: playbook: q: - - name: touch manifest - register: manifest + - name: touch compose + register: compose ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.dbms.manifest.yaml' - - name: create manifest + suffix: '{{ SELF.cache_name }}.compose.yaml' + - name: create compose ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: | - {{ deployment | to_yaml }} - --- - {{ service | to_yaml }} + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' vars: - deployment: - apiVersion: apps/v1 - kind: Deployment - metadata: - name: '{{ SELF.dbms_name }}' - namespace: default - spec: - selector: - matchLabels: - app: '{{ SELF.dbms_name }}' - template: - metadata: - labels: - app: '{{ SELF.dbms_name }}' - spec: - containers: - - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - name: '{{ SELF.dbms_name }}' - env: - - name: MYSQL_ROOT_PASSWORD - value: '{{ SELF.dbms_password }}' - ports: - - containerPort: 3306 - name: mysql - service: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.dbms_name }}' - spec: - ports: - - name: mysql - port: 3306 - targetPort: 3306 - selector: - app: '{{ SELF.dbms_name }}' - type: ClusterIP - - name: apply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} - args: - executable: /usr/bin/bash - - name: wait for deployment - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} rollout status deployment/{{ SELF.dbms_name }} --timeout 60s + manifest: + name: '{{ SELF.cache_name }}' + services: + application: + container_name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + environment: + APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' + APPLICATION_NAME: '"{{ SELF.application_name }}"' + APPLICATION_PORT: '"{{ SELF.application_port }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d args: executable: /usr/bin/bash - - name: let it cook - ansible.builtin.pause: - seconds: 10 delete: implementation: primary: Ansible @@ -7885,97 +23261,43 @@ node_types: inputs: playbook: q: - - name: touch manifest - register: manifest + - name: touch compose + register: compose ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.dbms.manifest.yaml' - - name: create manifest + suffix: '{{ SELF.cache_name }}.compose.yaml' + - name: create compose ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: | - {{ deployment | to_yaml }} - --- - {{ service | to_yaml }} + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' vars: - deployment: - apiVersion: apps/v1 - kind: Deployment - metadata: - name: '{{ SELF.dbms_name }}' - namespace: default - spec: - selector: - matchLabels: - app: '{{ SELF.dbms_name }}' - template: - metadata: - labels: - app: '{{ SELF.dbms_name }}' - spec: - containers: - - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - name: '{{ SELF.dbms_name }}' - env: - - name: MYSQL_ROOT_PASSWORD - value: '{{ SELF.dbms_password }}' - ports: - - containerPort: 3306 - name: mysql - service: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.dbms_name }}' - spec: - ports: - - name: mysql - port: 3306 - targetPort: 3306 - selector: - app: '{{ SELF.dbms_name }}' - type: ClusterIP - - name: unapply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + manifest: + name: '{{ SELF.cache_name }}' + services: + application: + container_name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + environment: + APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' + APPLICATION_NAME: '"{{ SELF.application_name }}"' + APPLICATION_PORT: '"{{ SELF.application_port }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash - mysql.dbms~mysql.dbms#dbms.image::terraform@kubernetes.cluster: - derived_from: mysql.dbms + redis.server~redis.server#cache.image::terraform@docker.engine->local.machine: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: - type: string - default: - get_input: k8s_client_key_file attributes: application_address: type: string - default: - eval: .::dbms_name - application_port: - type: integer - default: 3306 - management_address: - type: string - default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port + default: 127.0.0.1 interfaces: Standard: operations: @@ -7990,53 +23312,31 @@ node_types: main: terraform: - required_providers: - - kubernetes: - source: hashicorp/kubernetes - version: 2.31.0 - required_version: '>= 0.14.0' + - docker: + source: kreuzwerker/docker + version: 3.0.2 provider: - kubernetes: - - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} - client_key: ${file("{{ SELF.k8s_client_key_file }}")} - cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} - host: '{{ SELF.k8s_host }}' + docker: + - host: unix:///var/run/docker.sock resource: - kubernetes_deployment_v1: - application: - - metadata: - - name: '{{ SELF.dbms_name }}' - spec: - - selector: - - match_labels: - app: '{{ SELF.dbms_name }}' - template: - - metadata: - - labels: - app: '{{ SELF.dbms_name }}' - spec: - - container: - - name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - env: - - name: MYSQL_ROOT_PASSWORD - value: '{{ SELF.dbms_password }}' - port: - - container_port: 3306 - name: mysql - kubernetes_service_v1: + docker_container: application: - - metadata: - - name: '{{ SELF.dbms_name }}' - spec: - - port: - - name: mysql - port: 3306 - target_port: 3306 - selector: - app: '{{ SELF.dbms_name }}' - type: ClusterIP - mysql.dbms~mysql.dbms#dbms.image::ansible@remote.machine: - derived_from: mysql.dbms + - env: + - APPLICATION_PROTOCOL={{ SELF.application_protocol }} + - APPLICATION_NAME={{ SELF.application_name }} + - APPLICATION_PORT={{ SELF.application_port }} + image: ${docker_image.image.image_id} + name: '{{ SELF.cache_name }}' + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + network_mode: host + docker_image: + image: + - name: redis:{{ ".artifacts::cache_image::file" | eval }} + redis.server~redis.server#cache.image::ansible@docker.engine->remote.machine: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -8049,28 +23349,10 @@ node_types: type: string default: get_input: os_ssh_key_file - application_port: - type: string - default: 3001 + attributes: application_address: type: string default: 127.0.0.1 - attributes: - management_address: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: - eval: .::application_port - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address interfaces: Standard: operations: @@ -8085,66 +23367,16 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: installing mysql - ansible.builtin.apt: - name: - - mysql-server - - mysql-client - - python3-mysqldb - - libmysqlclient-dev - state: present - update_cache: 'yes' - - name: start and enable mysql service - ansible.builtin.systemd: - name: mysql - state: started - enabled: 'yes' - - name: enable passwordless login - ansible.builtin.copy: - dest: '{{ item }}' - content: | - [client] - user=root - password={{ SELF.dbms_password }} - loop: - - /root/.my.cnf - - /home/{{ SELF.os_ssh_user }}/.my.cnf - - name: configure port (e.g., since 3306 is blocked by the provider) - ansible.builtin.lineinfile: - path: /etc/mysql/mysql.conf.d/mysqld.cnf - regexp: ^# port - line: port = {{ SELF.application_port }} - backup: 'yes' - - name: enable remote login - ansible.builtin.lineinfile: - path: /etc/mysql/mysql.conf.d/mysqld.cnf - regexp: ^bind-address - line: bind-address = 0.0.0.0 - backup: 'yes' - - name: restart mysql - ansible.builtin.systemd: - name: mysql - state: restarted - - name: create all root - community.mysql.mysql_user: - name: root - password: '{{ SELF.dbms_password }}' - priv: '*.*:ALL' - host: '%' - state: present - login_host: localhost - login_password: '{{ SELF.dbms_password }}' - login_port: '{{ SELF.application_port }}' - login_user: root - - name: delete localhost root - community.mysql.mysql_user: - name: root - host: localhost - state: absent - login_host: localhost - login_password: '{{ SELF.dbms_password }}' - login_port: '{{ SELF.application_port }}' - login_user: root + - name: start container + community.docker.docker_container: + name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: redis --port {{ SELF.application_port }} + env: + APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' + APPLICATION_NAME: '"{{ SELF.application_name }}"' + APPLICATION_PORT: '"{{ SELF.application_port }}"' playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' @@ -8160,27 +23392,107 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: uninstalling mysql - ansible.builtin.apt: - name: - - mysql-server - - mysql-client - - python3-mysqldb - - libmysqlclient-dev - state: absent - - name: remove passwordless login - ansible.builtin.file: - name: '{{ item }}' + - name: stop container + community.docker.docker_container: + name: '{{ SELF.cache_name }}' state: absent - loop: - - /root/.my.cnf - - /home/{{ SELF.os_ssh_user }}/.my.cnf playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~mysql.dbms#dbms.image::terraform@remote.machine: - derived_from: mysql.dbms + redis.server~redis.server#cache.image::compose@docker.engine->remote.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.cache_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.cache_name }}' + services: + application: + container_name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + environment: + APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' + APPLICATION_NAME: '"{{ SELF.application_name }}"' + APPLICATION_PORT: '"{{ SELF.application_port }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.cache_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.cache_name }}' + services: + application: + container_name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + environment: + APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' + APPLICATION_NAME: '"{{ SELF.application_name }}"' + APPLICATION_PORT: '"{{ SELF.application_port }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + redis.server~redis.server#cache.image::terraform@docker.engine->remote.machine: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -8197,28 +23509,10 @@ node_types: type: string default: eval: .::.requirements::[.name=host]::.target::management_address - application_port: - type: string - default: 3001 + attributes: application_address: type: string default: 127.0.0.1 - attributes: - management_address: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: - eval: .::application_port - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address interfaces: Standard: operations: @@ -8231,495 +23525,532 @@ node_types: defaults: inputs: main: - resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - content: | - - #!/usr/bin/bash - set -e - export DEBIAN_FRONTEND="noninteractive" - - DBMS_PASSWORD=$1 - DBMS_PORT=$2 - - # Set password - debconf-set-selections <<< "mysql-server mysql-server/root_password password ${DBMS_PASSWORD}" - debconf-set-selections <<< "mysql-server mysql-server/root_password_again password ${DBMS_PASSWORD}" - - # Install mysql - apt-get update -y - apt-get -y install mysql-server - - # Passwordless auth - cat < /root/.my.cnf - [client] - user=root - password=${DBMS_PASSWORD} - EOF - - # Listen on all interfaces - sed -i "s/127\.0\.0\.1/0\.0\.0\.0/g" /etc/mysql/mysql.conf.d/mysqld.cnf - - # Listen on custom port - sed -i "s/# port.*/port = ${DBMS_PORT}/g" /etc/mysql/mysql.conf.d/mysqld.cnf - - # Configure any host for root - mysql -u root -e 'USE mysql; UPDATE user SET host = "%" WHERE user = "root"; FLUSH PRIVILEGES;' - mysql -u root -e 'USE mysql; DELETE FROM user WHERE user = "root" and host = "localhost"; FLUSH PRIVILEGES;' - - # Enable service - systemctl enable mysql - - # Restart service - systemctl restart mysql - destination: /tmp/install-mysql-dbms.sh - remote-exec: - - inline: - - sudo bash /tmp/install-mysql-dbms.sh {{ SELF.dbms_password }} {{ SELF.application_port }} - mysql.dbms~software.application#apt.package::ansible@*->remote.machine: - derived_from: mysql.dbms + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + provider: + docker: + - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 + ssh_opts: + - '-i' + - '{{ SELF.os_ssh_key_file }}' + - '-o' + - IdentitiesOnly=yes + - '-o' + - BatchMode=yes + - '-o' + - UserKnownHostsFile=/dev/null + - '-o' + - StrictHostKeyChecking=no + resource: + docker_container: + application: + - env: + - APPLICATION_PROTOCOL={{ SELF.application_protocol }} + - APPLICATION_NAME={{ SELF.application_name }} + - APPLICATION_PORT={{ SELF.application_port }} + image: ${docker_image.image.image_id} + name: '{{ SELF.cache_name }}' + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + network_mode: host + docker_image: + image: + - name: redis:{{ ".artifacts::cache_image::file" | eval }} + redis.server~redis.server#cache.image::ansible@gcp.memorystore: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + gcp_service_account_file: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: gcp_service_account_file + gcp_region: type: string default: - get_input: os_ssh_key_file - application_directory: + get_input: gcp_region + gcp_project: type: string default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name + get_input: gcp_project interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: run setup script - ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - args: - executable: /bin/bash - when: '".artifacts::apt_package::script" | eval != ""' - - name: add apt key - ansible.builtin.apt_key: - url: '{{ ".artifacts::apt_package::key" | eval }}' - keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - state: present - when: '".artifacts::apt_package::key" | eval != ""' - - name: add apt repository - ansible.builtin.apt_repository: - repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} - filename: '{{ ".artifacts::apt_package::repository" | eval }}' - state: present - when: '".artifacts::apt_package::source" | eval != ""' - - name: update apt cache - ansible.builtin.apt: - update_cache: 'yes' - - name: install dependencies - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' - state: present - when: '".artifacts::apt_package::dependencies" | eval != ""' - - name: install package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: present - environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/create.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - mode: '0755' - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/create.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - configure: - implementation: - primary: Ansible - operation_host: HOST + operation_host: ORCHESTRATOR environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/configure.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - mode: '0755' - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/configure.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - start: + - name: create redis + google.cloud.gcp_redis_instance: + name: '{{ SELF.cache_name }}' + memory_size_gb: 1 + region: '{{ SELF.gcp_region }}' + project: '{{ SELF.gcp_project }}' + register: redis_info + - name: set attributes + set_fact: + application_endpoint: '{{ redis_info.host }}:{{ redis_info.port }}' + application_address: '{{ redis_info.host }}' + application_port: '{{ redis_info.port }}' + delete: implementation: primary: Ansible - operation_host: HOST + operation_host: ORCHESTRATOR environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/start.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - mode: '0755' - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/start.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - stop: + - name: delete redis + google.cloud.gcp_redis_instance: + name: '{{ SELF.cache_name }}' + project: '{{ SELF.gcp_project }}' + state: absent + redis.server~redis.server#cache.image::terraform@gcp.memorystore: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: implementation: - primary: Ansible - operation_host: HOST + primary: Terraform environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/stop.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - mode: '0755' - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/stop.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file delete: implementation: - primary: Ansible - operation_host: HOST + primary: Terraform environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/delete.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - mode: '0755' - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/delete.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - - name: uninstall package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~software.application#apt.archive::terraform@*->remote.machine: - derived_from: mysql.dbms + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_redis_instance: + cache: + - name: '{{ SELF.cache_name }}' + memory_size_gb: 1 + lifecycle: + prevent_destroy: true + output: + application_endpoint: + - value: ${google_redis_instance.cache.host}:${google_redis_instance.cache.port} + application_address: + - value: ${google_redis_instance.cache.host} + application_port: + - value: ${google_redis_instance.cache.port} + outputs: + application_endpoint: application_endpoint + application_address: application_address + application_port: application_port + redis.server~redis.server#cache.image::ansible@kubernetes.cluster: + derived_from: redis.server metadata: vintner_generated: 'true' + vintner_orchestrator: unfurl properties: - os_ssh_user: + k8s_host: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: os_ssh_key_file - os_ssh_host: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - application_directory: + get_input: k8s_client_cert_file + k8s_client_key_file: type: string default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: + eval: .::cache_name interfaces: Standard: operations: - configure: + create: implementation: - primary: Terraform + primary: Ansible + operation_host: ORCHESTRATOR + environment: + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file + inputs: + playbook: + q: + - name: create deployment + kubernetes.core.k8s: + wait: true + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.application_name }}' + template: + metadata: + labels: + app: '{{ SELF.application_name }}' + spec: + containers: + - image: redis:{{ ".artifacts::cache_image::file" | eval }} + name: '{{ SELF.application_name }}' + env: + - name: APPLICATION_PROTOCOL + value: '"{{ SELF.application_protocol }}"' + - name: APPLICATION_NAME + value: '"{{ SELF.application_name }}"' + - name: APPLICATION_PORT + value: '"{{ SELF.application_port }}"' + command: redis --port {{ SELF.application_port }} + ports: + - containerPort: '{{ SELF.application_port }}' + - name: create service + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP delete: implementation: - primary: Terraform - defaults: - inputs: - main: - resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - content: | - #!/usr/bin/bash - set -e - - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi - - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi - - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then - echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} - fi - - # Update apt cache - apt-get update -y - - # Install dependencies - if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then - apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y - fi - - # Install package - {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - DBMS_NAME="{{ SELF.dbms_name }}" - APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-mysql.dbms.sh - remote-exec: - - inline: - - sudo bash /tmp/create-mysql.dbms.sh - - sudo bash /tmp/configure-mysql.dbms.sh - - sudo bash /tmp/start-mysql.dbms.sh - - inline: - - sudo bash /tmp/stop-mysql.dbms.sh - - sudo bash /tmp/delete-mysql.dbms.sh - when: destroy - mysql.dbms~software.application#tar.archive::ansible@*->remote.machine: - derived_from: mysql.dbms + primary: Ansible + operation_host: ORCHESTRATOR + environment: + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file + inputs: + playbook: + q: + - name: delete service + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: Service + namespace: default + name: '{{ SELF.application_name }}' + - name: delete deployment + kubernetes.core.k8s: + state: absent + api_version: app/v1 + kind: Deployment + namespace: default + name: '{{ SELF.application_name }}' + redis.server~redis.server#cache.image::kubernetes@kubernetes.cluster: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: + eval: .::cache_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.application.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} + vars: + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.cache_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.cache_name }}' + template: + metadata: + labels: + app: '{{ SELF.cache_name }}' + spec: + containers: + - image: redis:{{ ".artifacts::cache_image::file" | eval }} + name: '{{ SELF.cache_name }}' + env: + - name: APPLICATION_PROTOCOL + value: '"{{ SELF.application_protocol }}"' + - name: APPLICATION_NAME + value: '"{{ SELF.application_name }}"' + - name: APPLICATION_PORT + value: '"{{ SELF.application_port }}"' + command: redis --port {{ SELF.application_port }} + ports: + - containerPort: '{{ SELF.cache_port }}' + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.cache_name }}' + namespace: default + spec: + ports: + - name: redis + port: '{{ SELF.cache_port }}' + targetPort: '{{ SELF.cache_port }}' + selector: + app: '{{ SELF.cache_name }}' + type: ClusterIP + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} rollout status deployment/{{ SELF.application_name }} --timeout 60s + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.application.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} + vars: + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.cache_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.cache_name }}' + template: + metadata: + labels: + app: '{{ SELF.cache_name }}' + spec: + containers: + - image: redis:{{ ".artifacts::cache_image::file" | eval }} + name: '{{ SELF.cache_name }}' + env: + - name: APPLICATION_PROTOCOL + value: '"{{ SELF.application_protocol }}"' + - name: APPLICATION_NAME + value: '"{{ SELF.application_name }}"' + - name: APPLICATION_PORT + value: '"{{ SELF.application_port }}"' + command: redis --port {{ SELF.application_port }} + ports: + - containerPort: '{{ SELF.cache_port }}' + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.cache_name }}' + namespace: default + spec: + ports: + - name: redis + port: '{{ SELF.cache_port }}' + targetPort: '{{ SELF.cache_port }}' + selector: + app: '{{ SELF.cache_name }}' + type: ClusterIP + - name: unapply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + redis.server~redis.server#cache.image::terraform@kubernetes.cluster: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + k8s_host: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: os_ssh_key_file + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: + eval: .::application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - kubernetes: + source: hashicorp/kubernetes + version: 2.31.0 + required_version: '>= 0.14.0' + provider: + kubernetes: + - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} + client_key: ${file("{{ SELF.k8s_client_key_file }}")} + cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} + host: '{{ SELF.k8s_host }}' + resource: + kubernetes_deployment_v1: + application: + - metadata: + - name: '{{ SELF.application_name }}' + spec: + - selector: + - match_labels: + app: '{{ SELF.application_name }}' + template: + - metadata: + - labels: + app: '{{ SELF.application_name }}' + spec: + - container: + - env: + - name: APPLICATION_PROTOCOL + value: '"{{ SELF.application_protocol }}"' + - name: APPLICATION_NAME + value: '"{{ SELF.application_name }}"' + - name: APPLICATION_PORT + value: '"{{ SELF.application_port }}"' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + name: '{{ SELF.application_name }}' + command: redis --port {{ SELF.application_port }} + port: + - container_port: '{{ SELF.application_port }}' + kubernetes_service_v1: + application: + - metadata: + - name: '{{ SELF.application_name }}' + spec: + - port: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + target_port: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP + redis.server~software.application#apt.package::ansible@*->local.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: application_directory: type: string default: @@ -8734,43 +24065,44 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") - - name: extract deployment artifact from URL in application directory - ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: |- - DBMS_NAME="{{ SELF.dbms_name }}" - APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -8787,21 +24119,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -8818,21 +24142,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -8853,21 +24169,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "stop" missing @@ -8876,245 +24184,237 @@ node_types: ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - mode: '0755' - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/stop.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - delete: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/delete.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - mode: '0755' - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/delete.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~software.application#tar.archive::terraform@*->remote.machine: - derived_from: mysql.dbms - metadata: - vintner_generated: 'true' - properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - application_directory: - type: string - default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform - delete: - implementation: - primary: Terraform - defaults: - inputs: - main: - resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-mysql.dbms - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - DBMS_NAME="{{ SELF.dbms_name }}" - APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-mysql.dbms -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-mysql.dbms.sh - remote-exec: + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + redis.server~software.application#apt.package::terraform@*->local.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-redis.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-redis.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-redis.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-redis.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-redis.server.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: - inline: - - sudo bash /tmp/create-mysql.dbms.sh - - sudo bash /tmp/configure-mysql.dbms.sh - - sudo bash /tmp/start-mysql.dbms.sh + - sudo bash /tmp/create-redis.server.sh + - sudo bash /tmp/configure-redis.server.sh + - sudo bash /tmp/start-redis.server.sh - inline: - - sudo bash /tmp/stop-mysql.dbms.sh - - sudo bash /tmp/delete-mysql.dbms.sh + - sudo bash /tmp/stop-redis.server.sh + - sudo bash /tmp/delete-redis.server.sh when: destroy - mysql.dbms~software.application#zip.archive::ansible@*->remote.machine: - derived_from: mysql.dbms + redis.server~software.application#apt.package::ansible@*->remote.machine: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -9149,38 +24449,40 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache ansible.builtin.apt: - name: unzip update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: |- - DBMS_NAME="{{ SELF.dbms_name }}" - APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -9333,12 +24635,16 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~software.application#zip.archive::terraform@*->remote.machine: - derived_from: mysql.dbms + redis.server~software.application#apt.package::terraform@*->remote.machine: + derived_from: redis.server metadata: vintner_generated: 'true' properties: @@ -9384,32 +24690,46 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-mysql.dbms - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + # Create application directory mkdir -p {{ SELF.application_directory }} # Create application environment cat < {{ SELF.application_directory }}/.env - DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + APPLICATION_PORT="{{ SELF.application_port }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::zip_archive::file" | eval }} - fi - - # Extract deployment artifact - unzip /tmp/artifact-mysql.dbms -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -9426,7 +24746,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-mysql.dbms.sh + destination: /tmp/create-redis.server.sh - content: | #!/usr/bin/bash set -e @@ -9444,17 +24764,11 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-mysql.dbms.sh + destination: /tmp/configure-redis.server.sh - content: | #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - # Copy operation cat < {{ SELF.application_directory }}/.vintner/start.sh #!/usr/bin/bash @@ -9468,17 +24782,11 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-mysql.dbms.sh + destination: /tmp/start-redis.server.sh - content: | #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - # Copy operation cat < {{ SELF.application_directory }}/.vintner/stop.sh #!/usr/bin/bash @@ -9492,7 +24800,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-mysql.dbms.sh + destination: /tmp/stop-redis.server.sh - content: | #!/usr/bin/bash set -e @@ -9513,197 +24821,176 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-mysql.dbms.sh + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-redis.server.sh remote-exec: - inline: - - sudo bash /tmp/create-mysql.dbms.sh - - sudo bash /tmp/configure-mysql.dbms.sh - - sudo bash /tmp/start-mysql.dbms.sh + - sudo bash /tmp/create-redis.server.sh + - sudo bash /tmp/configure-redis.server.sh + - sudo bash /tmp/start-redis.server.sh - inline: - - sudo bash /tmp/stop-mysql.dbms.sh - - sudo bash /tmp/delete-mysql.dbms.sh + - sudo bash /tmp/stop-redis.server.sh + - sudo bash /tmp/delete-redis.server.sh when: destroy - mysql.database~mysql.database::ansible@mysql.dbms->docker.engine->remote.machine: - derived_from: mysql.database + redis.server~software.application#tar.archive::ansible@*->local.machine: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: + application_directory: type: string default: - get_input: os_ssh_key_file + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR inputs: playbook: q: - name: wait for ssh wait_for_connection: - - name: install pip - apt: - name: python3-pip - state: present - - name: install pymysql - pip: - name: pymysql - state: present - - name: get dbms container info - community.docker.docker_container_info: - name: '{{ HOST.dbms_name }}' - register: dbms_container_info - - name: forward port - community.docker.docker_container: - name: '{{ HOST.dbms_name }}-port-forward' - image: nicolaka/netshoot:v0.13 - command: socat TCP6-LISTEN:3306,fork TCP:{{ HOST.dbms_name }}:3306 - ports: - - '{{ HOST.application_port }}:3306' - when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" - - name: create forwarding network - community.docker.docker_network: - name: '{{ HOST.dbms_name }}-port-forward' - connected: - - '{{ HOST.dbms_name }}-port-forward' - - '{{ HOST.dbms_name }}' - when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" - - name: create database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: create user (with privileges) - community.mysql.mysql_user: - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: unforward port - community.docker.docker_container: - name: '{{ HOST.dbms_name }}-port-forward' - image: nicolaka/netshoot:v0.13 - network_mode: host - state: absent - when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" - - name: remove forwarding network - community.docker.docker_network: - name: '{{ HOST.dbms_name }}-port-forward' - state: absent - when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - delete: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - name: wait for ssh wait_for_connection: - - name: delete user (with privileges) - community.mysql.mysql_user: - state: absent - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: delete database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' - state: absent - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.database~mysql.database::compose@mysql.dbms->docker.engine->remote.machine: - derived_from: mysql.database - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - interfaces: - Standard: - operations: - create: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' - - name: create compose + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - services: - job: - container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - image: mysql:{{ HOST.dbms_version }} - network_mode: host - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d - args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - - name: give job some time - ansible.builtin.pause: - seconds: 10 - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" delete: implementation: primary: Ansible @@ -9711,63 +24998,41 @@ node_types: inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' - - name: create compose + - name: wait for ssh + wait_for_connection: + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - services: - job: - container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - image: mysql:{{ HOST.dbms_version }} - network_mode: host - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d - args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - - name: give job some time - ansible.builtin.pause: - seconds: 10 - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - mysql.database~mysql.database::terraform@mysql.dbms->docker.engine->remote.machine: - derived_from: mysql.database + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + redis.server~software.application#tar.archive::terraform@*->local.machine: + derived_from: redis.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: + application_directory: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -9780,213 +25045,581 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - mysql: - source: petoju/mysql - version: 3.0.48 - ssh: - source: AndrewChubatiuk/ssh - version: 0.2.3 - data: - ssh_tunnel: - mysql: - - remote: - host: '{{ HOST.application_address }}' - port: '{{ HOST.application_port }}' - provider: - mysql: - - endpoint: ${data.ssh_tunnel.mysql.local.address} - password: '{{ HOST.dbms_password }}' - username: root - ssh: - - auth: - private_key: - content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} - server: - host: '{{ HOST.management_address }}' - port: 22 - user: '{{ SELF.os_ssh_user }}' resource: - mysql_database: - database: - - name: '{{ SELF.database_name }}' - mysql_user: - user: - - host: '%' - plaintext_password: '{{ SELF.database_password }}' - user: '{{ SELF.database_user }}' - mysql_grant: - user: - - database: '{{ SELF.database_name }}' - host: '%' - table: '*' - privileges: - - ALL - user: ${mysql_user.user.user} - mysql.database~mysql.database::ansible@mysql.dbms->gcp.cloudsql: - derived_from: mysql.database + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-redis.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-redis.server {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-redis.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-redis.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-redis.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-redis.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-redis.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-redis.server.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-redis.server.sh + - sudo bash /tmp/configure-redis.server.sh + - sudo bash /tmp/start-redis.server.sh + - inline: + - sudo bash /tmp/stop-redis.server.sh + - sudo bash /tmp/delete-redis.server.sh + when: destroy + redis.server~software.application#tar.archive::ansible@*->remote.machine: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: create a database - google.cloud.gcp_sql_database: - name: '{{ SELF.database_name }}' - charset: utf8 - instance: '{{ HOST.dbms_name }}' - project: '{{ SELF.gcp_project }}' - - name: install GCP CloudSQL Proxy - ansible.builtin.get_url: - url: https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.13.0/cloud-sql-proxy.linux.amd64 - dest: /tmp/gcp-cloudsql-proxy + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} mode: '0755' - - name: forward port - ansible.builtin.shell: '/tmp/gcp-cloudsql-proxy {{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }} --credentials-file {{ SELF.gcp_service_account_file }} --port 23306 ' - args: - executable: /usr/bin/bash - async: 30 - poll: 0 - - name: wait for port - ansible.builtin.wait_for: - host: 127.0.0.1 - port: 23306 - delay: 5 - timeout: 30 - - name: create user (with privileges) - community.mysql.mysql_user: - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: 127.0.0.1 - login_password: '{{ HOST.dbms_password }}' - login_port: 23306 - login_user: root - - name: unforward port - ansible.builtin.shell: pkill -f "/tmp/gcp-cloudsql-proxy {{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }}" + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: - executable: /usr/bin/bash - mysql.database~mysql.database::terraform@mysql.dbms->gcp.cloudsql: - derived_from: mysql.database + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + redis.server~software.application#tar.archive::terraform@*->remote.machine: + derived_from: redis.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + os_ssh_host: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: configure: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file delete: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file defaults: inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - mysql: - source: petoju/mysql - version: 3.0.48 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - mysql: - - endpoint: cloudsql://{{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }} - password: '{{ HOST.dbms_password }}' - username: root resource: - google_sql_database: - database: - - name: '{{ SELF.database_name }}' - instance: '{{ HOST.dbms_name }}' - google_sql_user: - user: - - host: '%' - instance: '{{ HOST.dbms_name }}' - name: '{{ SELF.database_name }}' - password: '{{ SELF.database_password }}' - mysql_grant: - user: - - database: '{{ SELF.database_name }}' - host: '%' - table: '*' - privileges: - - ALL - user: ${google_sql_user.user.name} - mysql.database~mysql.database::ansible@mysql.dbms->kubernetes.cluster: - derived_from: mysql.database + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-redis.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-redis.server {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-redis.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-redis.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-redis.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-redis.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-redis.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-redis.server.sh + remote-exec: + - inline: + - sudo bash /tmp/create-redis.server.sh + - sudo bash /tmp/configure-redis.server.sh + - sudo bash /tmp/start-redis.server.sh + - inline: + - sudo bash /tmp/stop-redis.server.sh + - sudo bash /tmp/delete-redis.server.sh + when: destroy + redis.server~software.application#zip.archive::ansible@*->local.machine: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: + application_directory: type: string default: - get_input: k8s_client_key_file + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -9997,185 +25630,171 @@ node_types: inputs: playbook: q: - - name: deploy database - block: - - name: forward port - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.dbms_name }} 23306:3306 - args: - executable: /usr/bin/bash - async: 30 - poll: 0 - - name: wait for port - ansible.builtin.wait_for: - host: 127.0.0.1 - port: 23306 - delay: 5 - timeout: 30 - - name: create database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' - login_host: 127.0.0.1 - login_password: '{{ HOST.dbms_password }}' - login_port: '23306' - login_user: root - - name: create user (with privileges) - community.mysql.mysql_user: - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: 127.0.0.1 - login_password: '{{ HOST.dbms_password }}' - login_port: '23306' - login_user: root - always: - - name: unforward port - ansible.builtin.shell: pkill -f "port-forward service/{{ HOST.dbms_name }}" - args: - executable: /usr/bin/bash - mysql.database~mysql.database::kubernetes@mysql.dbms->kubernetes.cluster: - derived_from: mysql.database - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: - type: string - default: - get_input: k8s_client_key_file - interfaces: - Standard: - operations: - create: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: touch manifest - register: manifest - ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.manifest.yaml' - - name: create manifest + - name: copy management operation ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: '{{ job | to_yaml }}' - vars: - job: - apiVersion: batch/v1 - kind: Job - metadata: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' - spec: - template: - spec: - restartPolicy: Never - containers: - - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' - image: mysql:{{ HOST.dbms_version }} - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; - - name: apply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} - args: - executable: /usr/bin/bash - - name: wait for deployment - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.database_name }}-{{ HOST.dbms_name }} - args: - executable: /usr/bin/bash - - name: cleanup - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh args: - executable: /usr/bin/bash - delete: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: touch manifest - register: manifest - ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.manifest.yaml' - - name: create manifest + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: '{{ job | to_yaml }}' - vars: - job: - apiVersion: batch/v1 - kind: Job - metadata: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' - spec: - template: - spec: - restartPolicy: Never - containers: - - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' - image: mysql:{{ HOST.dbms_version }} - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; - - name: apply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: - executable: /usr/bin/bash - - name: wait for deployment - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.database_name }}-{{ HOST.dbms_name }} + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: - executable: /usr/bin/bash - - name: cleanup - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: - executable: /usr/bin/bash - mysql.database~mysql.database::terraform@mysql.dbms->kubernetes.cluster: - derived_from: mysql.database + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + redis.server~software.application#zip.archive::terraform@*->local.machine: + derived_from: redis.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: + application_directory: type: string default: - get_input: k8s_client_key_file + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -10188,55 +25807,164 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - mysql: - source: petoju/mysql - version: 3.0.48 - provider: - mysql: - - endpoint: ${terraform_data.forward_port.input} - password: '{{ HOST.dbms_password }}' - username: root resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-redis.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-redis.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-redis.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-redis.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-redis.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-redis.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-redis.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-redis.server.sh terraform_data: - forward_port: - - input: 127.0.0.1:23306 - provisioner: - local-exec: - command: |- - (nohup kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.dbms_name }} 23306:3306 > /dev/null 2>&1 &) - sleep 5s - interpreter: - - /bin/bash - - '-c' - unforward_port: + local: - depends_on: - - mysql_grant.user + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: local-exec: - command: pkill -f "port-forward service/{{ HOST.dbms_name }}" - interpreter: - - /bin/bash - - '-c' - mysql_database: - database: - - name: '{{ SELF.database_name }}' - mysql_user: - user: - - host: '%' - plaintext_password: '{{ SELF.database_password }}' - user: '{{ SELF.database_user }}' - mysql_grant: - user: - - database: '{{ SELF.database_name }}' - host: '%' - table: '*' - privileges: - - ALL - user: ${mysql_user.user.user} - mysql.database~mysql.database::ansible@mysql.dbms->remote.machine: - derived_from: mysql.database + - inline: + - sudo bash /tmp/create-redis.server.sh + - sudo bash /tmp/configure-redis.server.sh + - sudo bash /tmp/start-redis.server.sh + - inline: + - sudo bash /tmp/stop-redis.server.sh + - sudo bash /tmp/delete-redis.server.sh + when: destroy + redis.server~software.application#zip.archive::ansible@*->remote.machine: + derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -10249,6 +25977,14 @@ node_types: type: string default: get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -10263,31 +25999,155 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install pip - apt: - name: python3-pip - state: present - - name: install pymysql - pip: - name: pymysql - state: present - - name: create database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: create user (with privileges) - community.mysql.mysql_user: - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' @@ -10303,34 +26163,34 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: delete user (with privileges) - community.mysql.mysql_user: - state: absent - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: delete database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' state: absent - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - mysql.database~mysql.database::terraform@mysql.dbms->remote.machine: - derived_from: mysql.database + redis.server~software.application#zip.archive::terraform@*->remote.machine: + derived_from: redis.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: os_ssh_user: type: string @@ -10344,6 +26204,14 @@ node_types: type: string default: eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -10356,47 +26224,151 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - mysql: - source: petoju/mysql - version: 3.0.48 - ssh: - source: AndrewChubatiuk/ssh - version: 0.2.3 - data: - ssh_tunnel: - mysql: - - remote: - host: '{{ HOST.application_address }}' - port: '{{ HOST.application_port }}' - provider: - mysql: - - endpoint: ${data.ssh_tunnel.mysql.local.address} - password: '{{ HOST.dbms_password }}' - username: root - ssh: - - auth: - private_key: - content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} - server: - host: '{{ HOST.management_address }}' - port: 22 - user: '{{ SELF.os_ssh_user }}' resource: - mysql_database: - database: - - name: '{{ SELF.database_name }}' - mysql_user: - user: - - host: '%' - plaintext_password: '{{ SELF.database_password }}' - user: '{{ SELF.database_user }}' - mysql_grant: - user: - - database: '{{ SELF.database_name }}' - host: '%' - table: '*' - privileges: - - ALL - user: ${mysql_user.user.user} + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-redis.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-redis.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-redis.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-redis.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-redis.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-redis.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-redis.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-redis.server.sh + remote-exec: + - inline: + - sudo bash /tmp/create-redis.server.sh + - sudo bash /tmp/configure-redis.server.sh + - sudo bash /tmp/start-redis.server.sh + - inline: + - sudo bash /tmp/stop-redis.server.sh + - sudo bash /tmp/delete-redis.server.sh + when: destroy diff --git a/examples/unfurl-technology---shop---plus-maintenance-automated/lib/shop.component.yaml b/examples/unfurl-technology---shop---plus-maintenance-automated/lib/shop.component.yaml index 3f2ede1f59..937d17e8e8 100644 --- a/examples/unfurl-technology---shop---plus-maintenance-automated/lib/shop.component.yaml +++ b/examples/unfurl-technology---shop---plus-maintenance-automated/lib/shop.component.yaml @@ -1115,6 +1115,414 @@ node_types: selector: app: '{{ SELF.application_name }}' type: ClusterIP + shop.component~service.application#tar.archive::ansible@*->local.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + shop.component~service.application#tar.archive::terraform@*->local.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-shop.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shop.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-shop.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-shop.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shop.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-shop.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-shop.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-shop.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-shop.component.sh + - sudo bash /tmp/configure-shop.component.sh + - sudo bash /tmp/start-shop.component.sh + - inline: + - sudo bash /tmp/stop-shop.component.sh + - sudo bash /tmp/delete-shop.component.sh + when: destroy shop.component~service.application#tar.archive::ansible@*->remote.machine: derived_from: shop.component metadata: @@ -1143,31 +1551,481 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + shop.component~service.application#tar.archive::terraform@*->remote.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-shop.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shop.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-shop.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-shop.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-shop.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-shop.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-shop.component.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-shop.component.sh + remote-exec: + - inline: + - sudo bash /tmp/create-shop.component.sh + - sudo bash /tmp/configure-shop.component.sh + - sudo bash /tmp/start-shop.component.sh + - inline: + - sudo bash /tmp/stop-shop.component.sh + - sudo bash /tmp/delete-shop.component.sh + when: destroy + shop.component~service.application#zip.archive::ansible@*->local.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1222,21 +2080,13 @@ node_types: state: stopped enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -1253,21 +2103,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -1282,27 +2124,29 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: started enabled: 'yes' daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1323,21 +2167,13 @@ node_types: ansible.builtin.systemd: name: '{{ SELF.application_name }}' state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1354,6 +2190,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1361,31 +2201,11 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - shop.component~service.application#tar.archive::terraform@*->remote.machine: + shop.component~service.application#zip.archive::terraform@*->local.machine: derived_from: shop.component metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1407,154 +2227,164 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-shop.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shop.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-shop.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-shop.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shop.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-shop.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-shop.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-shop.component.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-shop.component - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - PORT="{{ SELF.application_port }}" - DB_DIALECT="{{ SELF.DB_DIALECT }}" - DB_NAME="{{ SELF.DB_NAME }}" - DB_USERNAME="{{ SELF.DB_USERNAME }}" - DB_PASSWORD="{{ SELF.DB_PASSWORD }}" - DB_ADDRESS="{{ SELF.DB_ADDRESS }}" - DB_PORT="{{ SELF.DB_PORT }}" - FEATURE_OPTIONAL="{{ SELF.optional_feature }}" - FEATURE_PREMIUM="{{ SELF.premium_feature }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-shop.component {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-shop.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-shop.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-shop.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-shop.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-shop.component.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-shop.component.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-shop.component.sh - sudo bash /tmp/configure-shop.component.sh @@ -1613,12 +2443,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1733,6 +2564,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: start service ansible.builtin.systemd: name: '{{ SELF.application_name }}' @@ -1754,6 +2591,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1805,6 +2646,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent - name: delete systemd service ansible.builtin.file: path: /etc/systemd/system/{{ SELF.application_name }}.service @@ -1812,10 +2657,6 @@ node_types: - name: reload daemon ansible.builtin.systemd: daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' @@ -2171,49 +3012,423 @@ node_types: application_endpoint: - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: - DB_DIALECT: '"{{ SELF.DB_DIALECT }}"' - DB_NAME: '"{{ SELF.DB_NAME }}"' - DB_USERNAME: '"{{ SELF.DB_USERNAME }}"' - DB_PASSWORD: '"{{ SELF.DB_PASSWORD }}"' - DB_ADDRESS: '"{{ SELF.DB_ADDRESS }}"' - DB_PORT: '"{{ SELF.DB_PORT }}"' - FEATURE_OPTIONAL: '"{{ SELF.optional_feature }}"' - FEATURE_PREMIUM: '"{{ SELF.premium_feature }}"' - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + DB_DIALECT: '"{{ SELF.DB_DIALECT }}"' + DB_NAME: '"{{ SELF.DB_NAME }}"' + DB_USERNAME: '"{{ SELF.DB_USERNAME }}"' + DB_PASSWORD: '"{{ SELF.DB_PASSWORD }}"' + DB_ADDRESS: '"{{ SELF.DB_ADDRESS }}"' + DB_PORT: '"{{ SELF.DB_PORT }}"' + FEATURE_OPTIONAL: '"{{ SELF.optional_feature }}"' + FEATURE_PREMIUM: '"{{ SELF.premium_feature }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + shop.component~software.application#apt.package::ansible@*->local.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + shop.component~software.application#apt.package::terraform@*->local.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-shop.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shop.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-shop.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-shop.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-shop.component.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-shop.component.sh + - sudo bash /tmp/configure-shop.component.sh + - sudo bash /tmp/start-shop.component.sh + - inline: + - sudo bash /tmp/stop-shop.component.sh + - sudo bash /tmp/delete-shop.component.sh + when: destroy shop.component~software.application#apt.package::ansible@*->remote.machine: derived_from: shop.component metadata: @@ -2346,6 +3561,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -2377,6 +3596,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -2436,7 +3659,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - shop.component~software.application#apt.archive::terraform@*->remote.machine: + shop.component~software.application#apt.package::terraform@*->remote.machine: derived_from: shop.component metadata: vintner_generated: 'true' @@ -2529,14 +3752,6 @@ node_types: FEATURE_PREMIUM="{{ SELF.premium_feature }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-shop.component {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2641,6 +3856,385 @@ node_types: - sudo bash /tmp/stop-shop.component.sh - sudo bash /tmp/delete-shop.component.sh when: destroy + shop.component~software.application#tar.archive::ansible@*->local.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + shop.component~software.application#tar.archive::terraform@*->local.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-shop.component + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shop.component {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-shop.component -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-shop.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shop.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-shop.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-shop.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-shop.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-shop.component.sh + - sudo bash /tmp/configure-shop.component.sh + - sudo bash /tmp/start-shop.component.sh + - inline: + - sudo bash /tmp/stop-shop.component.sh + - sudo bash /tmp/delete-shop.component.sh + when: destroy shop.component~software.application#tar.archive::ansible@*->remote.machine: derived_from: shop.component metadata: @@ -3058,6 +4652,375 @@ node_types: - sudo bash /tmp/stop-shop.component.sh - sudo bash /tmp/delete-shop.component.sh when: destroy + shop.component~software.application#zip.archive::ansible@*->local.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + shop.component~software.application#zip.archive::terraform@*->local.machine: + derived_from: shop.component + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-shop.component + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + PORT="{{ SELF.application_port }}" + DB_DIALECT="{{ SELF.DB_DIALECT }}" + DB_NAME="{{ SELF.DB_NAME }}" + DB_USERNAME="{{ SELF.DB_USERNAME }}" + DB_PASSWORD="{{ SELF.DB_PASSWORD }}" + DB_ADDRESS="{{ SELF.DB_ADDRESS }}" + DB_PORT="{{ SELF.DB_PORT }}" + FEATURE_OPTIONAL="{{ SELF.optional_feature }}" + FEATURE_PREMIUM="{{ SELF.premium_feature }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-shop.component {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-shop.component -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-shop.component.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-shop.component.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-shop.component.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-shop.component.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-shop.component.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-shop.component.sh + - sudo bash /tmp/configure-shop.component.sh + - sudo bash /tmp/start-shop.component.sh + - inline: + - sudo bash /tmp/stop-shop.component.sh + - sudo bash /tmp/delete-shop.component.sh + when: destroy shop.component~software.application#zip.archive::ansible@*->remote.machine: derived_from: shop.component metadata: @@ -3108,12 +5071,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' diff --git a/examples/unfurl-technology---shop---plus-maintenance-automated/lib/technology-rules.yaml b/examples/unfurl-technology---shop---plus-maintenance-automated/lib/technology-rules.yaml index bd593ee0f0..b2587923ee 100644 --- a/examples/unfurl-technology---shop---plus-maintenance-automated/lib/technology-rules.yaml +++ b/examples/unfurl-technology---shop---plus-maintenance-automated/lib/technology-rules.yaml @@ -4,64 +4,6 @@ # ################################################### -- technology: ansible - component: bucket - hosting: - - gcp.cloudstorage - weight: 0.5 - reason: Primary use case due to the specialization of Ansible. However, need to install and handle GCP CloudSQL Proxy, while the corresponding Terraform module already provides this. -- technology: terraform - component: bucket - hosting: - - gcp.cloudstorage - weight: 1 - reason: Terraform provides a declarative module. -- technology: ansible - component: bucket - hosting: - - minio.server - - '*' - - local.machine - weight: 1 - reason: Primary use case due to the specialization of Ansible. -- technology: terraform - component: bucket - hosting: - - minio.server - - '*' - - local.machine - weight: 1 - reason: Terraform provides a declarative module. -- technology: ansible - component: bucket - hosting: - - minio.server - - '*' - - remote.machine - weight: 1 - reason: Primary use case due to the specialization of Ansible. -- technology: terraform - component: bucket - hosting: - - minio.server - - '*' - - remote.machine - weight: 1 - reason: Terraform provides a declarative module. -- technology: ansible - component: bucket - hosting: - - minio.server - - kubernetes.cluster - weight: 1 - reason: Primary use case due to the specialization of Ansible. -- technology: terraform - component: bucket - hosting: - - minio.server - - kubernetes.cluster - weight: 1 - reason: Terraform provides a declarative module. - technology: ansible component: docker.engine hosting: @@ -123,6 +65,20 @@ weight: 0.5 reason: Kubernetes is more specialized. details: '"kubernetes_service_v1" resource' +- technology: ansible + component: ingress + hosting: + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. + details: '"ansible.builtin.apt_key", "ansible.builtin.apt_repository", "ansible.builtin.apt", "ansible.builtin.copy", and "ansible.builtin.systemd" tasks' +- technology: terraform + component: ingress + hosting: + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" resource to create the installation script and "terraform_data" to execute the script using the "local-exec" provisioner' - technology: ansible component: ingress hosting: @@ -159,8 +115,8 @@ - mysql.dbms - docker.engine - local.machine - weight: 0.5 - reason: Terraform provides a declarative module. However, Terraform requires an SSH workaround. Ansible is more specialized. + weight: 1 + reason: Terraform provides a declarative module. - technology: ansible component: mysql.database hosting: @@ -220,6 +176,20 @@ - kubernetes.cluster weight: 0 reason: Ansible is more specialized. +- technology: ansible + component: mysql.database + hosting: + - mysql.dbms + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: terraform + component: mysql.database + hosting: + - mysql.dbms + - local.machine + weight: 1 + reason: Terraform provides a declarative module. - technology: ansible component: mysql.database hosting: @@ -328,6 +298,22 @@ weight: 0.5 reason: Kubernetes is more specialized. details: '"kubernetes_deployment_v1" and "kubernetes_service_v1" resources' +- technology: ansible + component: mysql.dbms + artifact: dbms.image + hosting: + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. + details: '"ansible.builtin.apt", "ansible.builtin.systemd", "ansible.builtin.copy", "ansible.builtin.lineinfile", and "community.mysql.mysql_user" tasks' +- technology: terraform + component: mysql.dbms + artifact: dbms.image + hosting: + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" resource to create the installation script and "terraform_data" to execute the script using the "local-exec" provisioner' - technology: ansible component: mysql.dbms artifact: dbms.image @@ -345,19 +331,86 @@ reason: Ansible is more specialized. Also using provisioners is a "last resort". details: '"terraform_data" resource with an "ssh" connection to the virtual machine to copy the install script using the "file" provisioner on the virtual machine and to execute the script using the "remote-exec" provisioner' - technology: ansible - component: bucket - artifact: cache.image + component: object.storage hosting: - - gcp.memorystore - weight: 0.5 - reason: Primary use case due to the specialization of Ansible. However, need to install and handle GCP CloudSQL Proxy, while the corresponding Terraform module already provides this. + - gcp.cloudstorage + weight: 1 + reason: Primary use case due to the specialization of Ansible. - technology: terraform - component: redis.server - artifact: cache.image + component: object.storage hosting: - - gcp.memorystore + - gcp.cloudstorage weight: 1 reason: Terraform provides a declarative module. +- technology: ansible + component: object.storage + hosting: + - minio.server + - docker.engine + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: compose + component: object.storage + hosting: + - minio.server + - docker.engine + - local.machine + weight: 0 + reason: One-time use docker container ("fake Kubernetes job") with imperative parts, while other technologies provide declarative modules. +- technology: terraform + component: object.storage + hosting: + - minio.server + - docker.engine + - local.machine + weight: 1 + reason: Terraform provides a declarative module. +- technology: ansible + component: object.storage + hosting: + - minio.server + - docker.engine + - remote.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: compose + component: object.storage + hosting: + - minio.server + - docker.engine + - remote.machine + weight: 0 + reason: One-time use docker container ("fake Kubernetes job") with imperative parts, while other technologies provide declarative modules. +- technology: terraform + component: object.storage + hosting: + - minio.server + - docker.engine + - remote.machine + weight: 0.5 + reason: Terraform provides a declarative module. However, Terraform requires an SSH workaround. Ansible is more specialized. +- technology: ansible + component: object.storage + hosting: + - minio.server + - kubernetes.cluster + weight: 1 + reason: Primary use case due to the specialization of Ansible. +- technology: kubernetes + component: object.storage + hosting: + - minio.server + - kubernetes.cluster + weight: 0 + reason: Kubernetes Job with imperative parts, while declarative other technologies provide declarative modules. +- technology: terraform + component: object.storage + hosting: + - minio.server + - kubernetes.cluster + weight: 0 + reason: Ansible is more specialized. - technology: ansible component: redis.server artifact: cache.image @@ -416,16 +469,38 @@ component: redis.server artifact: cache.image hosting: - - kubernetes.cluster + - gcp.memorystore weight: 1 reason: Primary use case due to the specialization of Ansible. - technology: terraform component: redis.server artifact: cache.image hosting: - - kubernetes.cluster + - gcp.memorystore weight: 1 reason: Terraform provides a declarative module. +- technology: ansible + component: redis.server + artifact: cache.image + hosting: + - kubernetes.cluster + weight: 0.5 + reason: Kubernetes is more specialized. +- technology: kubernetes + component: redis.server + artifact: cache.image + hosting: + - kubernetes.cluster + weight: 1 + reason: Kubernetes is the underlying technology. + details: Kubernetes manifest generated and applied +- technology: terraform + component: redis.server + artifact: cache.image + hosting: + - kubernetes.cluster + weight: 0.5 + reason: Kubernetes is more specialized. - technology: ansible component: service.application artifact: docker.image @@ -520,6 +595,24 @@ weight: 0.5 reason: Kubernetes is more specialized. details: '"kubernetes_deployment_v1" and "kubernetes_service_v1" resources' +- technology: ansible + component: service.application + artifact: tar.archive + hosting: + - '*' + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. Special integration for systemd. + details: '"ansible.builtin.file", "ansible.builtin.unarchive", "ansible.builtin.copy", "ansible.builtin.fail", "ansible.builtin.shell", and "ansible.builtin.systemd" tasks with "when" statements' +- technology: terraform + component: service.application + artifact: tar.archive + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts.' - technology: ansible component: service.application artifact: tar.archive @@ -538,6 +631,24 @@ weight: 0 reason: Ansible is more specialized. Also using provisioners is a "last resort". details: '"file" provisioner to upload artifacts and scripts and "remote-exec" to execute scripts' +- technology: ansible + component: service.application + artifact: zip.archive + hosting: + - '*' + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. Special integration for systemd. + details: '"ansible.builtin.file", "ansible.builtin.unarchive", "ansible.builtin.copy", "ansible.builtin.fail", "ansible.builtin.shell", and "ansible.builtin.systemd" tasks with "when" statements' +- technology: terraform + component: service.application + artifact: zip.archive + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts.' - technology: ansible component: service.application artifact: zip.archive @@ -572,6 +683,24 @@ weight: 1 reason: Terraform provides a declarative module. details: '"google_app_engine_standard_app_version", "google_project_iam_member", "google_service_account", "google_storage_bucket", and "google_storage_bucket_object" resources' +- technology: ansible + component: software.application + artifact: apt.package + hosting: + - '*' + - local.machine + weight: 1 + reason: Primary use case due to the specialization of Ansible. + details: '"ansible.builtin.shell", "ansible.builtin.apt_key", "ansible.builtin.apt_repository", "ansible.builtin.apt", and "ansible.builtin.copy", tasks with "when" statements' +- technology: terraform + component: software.application + artifact: apt.package + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts' - technology: ansible component: software.application artifact: apt.package @@ -583,13 +712,31 @@ details: '"ansible.builtin.shell", "ansible.builtin.apt_key", "ansible.builtin.apt_repository", "ansible.builtin.apt", and "ansible.builtin.copy", tasks with "when" statements' - technology: terraform component: software.application - artifact: apt.archive + artifact: apt.package hosting: - '*' - remote.machine weight: 0 reason: Ansible is more specialized. Also using provisioners is a "last resort". details: '"file" provisioner to upload scripts and "remote-exec" to execute scripts' +- technology: ansible + component: software.application + artifact: tar.archive + hosting: + - '*' + - local.machine + weight: 0.5 + reason: While this is a primary use case due to the specialization of Ansible, we must rely on scripts. More specialized types should be used, e.g., service.application. + details: '"ansible.builtin.apt", "ansible.builtin.file", "ansible.builtin.unarchive", "ansible.builtin.copy", "ansible.builtin.fail", and "ansible.builtin.shell" tasks with "when" statements' +- technology: terraform + component: software.application + artifact: tar.archive + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts' - technology: ansible component: software.application artifact: tar.archive @@ -608,6 +755,24 @@ weight: 0 reason: Ansible is more specialized. Also using provisioners is a "last resort". details: '"file" provisioner to upload artifacts and scripts and "remote-exec" to execute scripts' +- technology: ansible + component: software.application + artifact: zip.archive + hosting: + - '*' + - local.machine + weight: 0.5 + reason: While this is a primary use case due to the specialization of Ansible, we must rely on scripts. More specialized types should be used, e.g., service.application. + details: '"ansible.builtin.apt", "ansible.builtin.file", "ansible.builtin.unarchive", "ansible.builtin.copy", "ansible.builtin.fail", and "ansible.builtin.shell" tasks with "when" statements' +- technology: terraform + component: software.application + artifact: zip.archive + hosting: + - '*' + - local.machine + weight: 0 + reason: Ansible is more specialized. Also using provisioners is a "last resort". + details: '"local_file" module to create scripts and artifacts and "local-exec" provisioner to execute scripts.' - technology: ansible component: software.application artifact: zip.archive diff --git a/examples/unfurl-technology---shop---plus-maintenance-automated/lib/tosca-vintner-profile-core.yaml b/examples/unfurl-technology---shop---plus-maintenance-automated/lib/tosca-vintner-profile-core.yaml index eb2789c44f..8bbae12e3c 100644 --- a/examples/unfurl-technology---shop---plus-maintenance-automated/lib/tosca-vintner-profile-core.yaml +++ b/examples/unfurl-technology---shop---plus-maintenance-automated/lib/tosca-vintner-profile-core.yaml @@ -311,32 +311,57 @@ node_types: vintner_abstract: 'true' cache: derived_from: software.application + properties: + cache_name: + type: string + cache_port: + type: string + attributes: + application_endpoint: + type: string + default: + concat: + - eval: .::application_protocol + - '://' + - eval: .::application_address + - ':' + - eval: .::application_port + application_address: + type: string storage: derived_from: node + metadata: + vintner_normative: 'true' block.storage: derived_from: storage + metadata: + vintner_normative: 'true' object.storage: derived_from: storage - file.storage: - derived_from: storage - bucket: - derived_from: object.storage metadata: vintner_normative: 'true' properties: - bucket_name: + storage_name: + type: string + storage_dialect: + type: string + storage_user: type: string - bucket_dialect: + storage_token: type: string attributes: - bucket_endpoint: + storage_endpoint: type: string - bucket_token: + storage_token: type: string requirements: - host: capability: tosca.capabilities.Compute relationship: tosca.relationships.HostedOn + file.storage: + derived_from: storage + metadata: + vintner_normative: 'true' ingress: derived_from: node metadata: @@ -587,20 +612,12 @@ node_types: openstack_networking_secgroup_v2: ports: - name: '{{ SELF.machine_name }}' - cache~software.application#apt.package::ansible@*->remote.machine: + cache~software.application#apt.package::ansible@*->local.machine: derived_from: cache metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -615,14 +632,10 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: run setup script ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - args: @@ -673,21 +686,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -704,21 +709,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -735,21 +736,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -766,21 +763,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -805,27 +794,11 @@ node_types: ansible.builtin.apt: name: '{{ ".artifacts::apt_package::file" | eval }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - cache~software.application#apt.archive::terraform@*->remote.machine: + cache~software.application#apt.package::terraform@*->local.machine: derived_from: cache metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -847,157 +820,157 @@ node_types: inputs: main: resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - content: | - #!/usr/bin/bash - set -e - - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi - - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi - - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then - echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} - fi + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e - # Update apt cache - apt-get update -y + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi - # Install dependencies - if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then - apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y - fi + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi - # Install package - {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi - # Create application directory - mkdir -p {{ SELF.application_directory }} + # Update apt cache + apt-get update -y - # Create application environment - cat < {{ SELF.application_directory }}/.env + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi - EOF>> + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-cache {{ ".artifacts::apt_archive::file" | eval }} - fi + # Create application directory + mkdir -p {{ SELF.application_directory }} - # Extract deployment artifact - undefined + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-cache.sh - - content: | - #!/usr/bin/bash - set -e + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-cache.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-cache.sh - - content: | - #!/usr/bin/bash - set -e + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cache.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-cache.sh - - content: | - #!/usr/bin/bash - set -e + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-cache.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-cache.sh - - content: | - #!/usr/bin/bash - set -e + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-cache.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh - # Delete application directory - rm -rf "{{ SELF.application_directory }}" + # Delete application directory + rm -rf "{{ SELF.application_directory }}" - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-cache.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-cache.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: - inline: - sudo bash /tmp/create-cache.sh - sudo bash /tmp/configure-cache.sh @@ -1006,7 +979,7 @@ node_types: - sudo bash /tmp/stop-cache.sh - sudo bash /tmp/delete-cache.sh when: destroy - cache~software.application#tar.archive::ansible@*->remote.machine: + cache~software.application#apt.package::ansible@*->remote.machine: derived_from: cache metadata: vintner_generated: 'true' @@ -1042,31 +1015,40 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") - - name: extract deployment artifact from URL in application directory - ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: '' + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -1219,11 +1201,15 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - cache~software.application#tar.archive::terraform@*->remote.machine: + cache~software.application#apt.package::terraform@*->remote.machine: derived_from: cache metadata: vintner_generated: 'true' @@ -1270,29 +1256,45 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-cache - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + # Create application directory mkdir -p {{ SELF.application_directory }} # Create application environment cat < {{ SELF.application_directory }}/.env - + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-cache {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-cache -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1332,12 +1334,6 @@ node_types: #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - # Copy operation cat < {{ SELF.application_directory }}/.vintner/start.sh #!/usr/bin/bash @@ -1356,12 +1352,6 @@ node_types: #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - # Copy operation cat < {{ SELF.application_directory }}/.vintner/stop.sh #!/usr/bin/bash @@ -1396,6 +1386,9 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y destination: /tmp/delete-cache.sh remote-exec: - inline: @@ -1406,20 +1399,12 @@ node_types: - sudo bash /tmp/stop-cache.sh - sudo bash /tmp/delete-cache.sh when: destroy - cache~software.application#zip.archive::ansible@*->remote.machine: + cache~software.application#tar.archive::ansible@*->local.machine: derived_from: cache metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -1434,9 +1419,7 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1452,16 +1435,17 @@ node_types: state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1469,7 +1453,9 @@ node_types: - name: create .env file ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' - content: '' + content: |- + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -1486,16 +1472,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1517,16 +1497,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1552,16 +1526,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1587,16 +1555,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1622,27 +1584,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - cache~software.application#zip.archive::terraform@*->remote.machine: + cache~software.application#tar.archive::terraform@*->local.machine: derived_from: cache metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1664,110 +1610,1284 @@ node_types: inputs: main: resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-cache - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-cache + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e - # Create application directory - mkdir -p {{ SELF.application_directory }} + # Create application directory + mkdir -p {{ SELF.application_directory }} - # Create application environment - cat < {{ SELF.application_directory }}/.env + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> - EOF>> + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cache {{ ".artifacts::tar_archive::file" | eval }} + fi - # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-cache {{ ".artifacts::zip_archive::file" | eval }} - fi + # Extract deployment artifact + tar -xzf /tmp/artifact-cache -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - # Extract deployment artifact - unzip /tmp/artifact-cache -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-cache.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-cache.sh - - content: | - #!/usr/bin/bash - set -e + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cache.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-cache.sh - - content: | - #!/usr/bin/bash - set -e + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-cache.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-cache.sh - - content: | - #!/usr/bin/bash - set -e + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-cache.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-cache.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-cache.sh + - sudo bash /tmp/configure-cache.sh + - sudo bash /tmp/start-cache.sh + - inline: + - sudo bash /tmp/stop-cache.sh + - sudo bash /tmp/delete-cache.sh + when: destroy + cache~software.application#tar.archive::ansible@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + cache~software.application#tar.archive::terraform@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-cache + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cache {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-cache -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-cache.sh + remote-exec: + - inline: + - sudo bash /tmp/create-cache.sh + - sudo bash /tmp/configure-cache.sh + - sudo bash /tmp/start-cache.sh + - inline: + - sudo bash /tmp/stop-cache.sh + - sudo bash /tmp/delete-cache.sh + when: destroy + cache~software.application#zip.archive::ansible@*->local.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + cache~software.application#zip.archive::terraform@*->local.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-cache + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cache {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-cache -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-cache.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-cache.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-cache.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-cache.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-cache.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-cache.sh + - sudo bash /tmp/configure-cache.sh + - sudo bash /tmp/start-cache.sh + - inline: + - sudo bash /tmp/stop-cache.sh + - sudo bash /tmp/delete-cache.sh + when: destroy + cache~software.application#zip.archive::ansible@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + cache~software.application#zip.archive::terraform@*->remote.machine: + derived_from: cache + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-cache + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + CACHE_NAME="{{ SELF.cache_name }}" + CACHE_PORT="{{ SELF.cache_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-cache {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-cache -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-cache.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash set -e {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} @@ -1809,8 +2929,8 @@ node_types: - sudo bash /tmp/stop-cache.sh - sudo bash /tmp/delete-cache.sh when: destroy - bucket~bucket::ansible@gcp.cloudstorage: - derived_from: bucket + object.storage~object.storage::ansible@gcp.cloudstorage: + derived_from: object.storage metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -1827,6 +2947,16 @@ node_types: type: string default: get_input: gcp_project + attributes: + storage_endpoint: + type: string + default: '{{ SELF.storage_name }}' + storage_token: + type: string + default: '' + storage_dialect: + type: string + default: gcp interfaces: Standard: operations: @@ -1840,7 +2970,12 @@ node_types: GCP_AUTH_KIND: serviceaccount inputs: playbook: - q: [] + q: + - name: create bucket + google.cloud.gcp_storage_bucket: + name: '{{ SELF.storage_name }}' + location: EU + project: '{{ SELF.gcp_project }}' delete: implementation: primary: Ansible @@ -1851,9 +2986,14 @@ node_types: GCP_AUTH_KIND: serviceaccount inputs: playbook: - q: [] - bucket~bucket::terraform@gcp.cloudstorage: - derived_from: bucket + q: + - name: delete bucket + google.cloud.gcp_storage_bucket: + name: '{{ SELF.storage_name }}' + project: '{{ SELF.gcp_project }}' + state: absent + object.storage~object.storage::terraform@gcp.cloudstorage: + derived_from: object.storage metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -1870,6 +3010,16 @@ node_types: type: string default: get_input: gcp_project + attributes: + storage_endpoint: + type: string + default: '{{ SELF.storage_name }}' + storage_token: + type: string + default: '' + storage_dialect: + type: string + default: gcp interfaces: Standard: operations: @@ -1893,33 +3043,22 @@ node_types: - google: source: hashicorp/google version: 5.39.1 - mysql: - source: petoju/mysql - version: 3.0.48 provider: google: - credentials: '{{ SELF.gcp_service_account_file }}' project: '{{ SELF.gcp_project }}' region: '{{ SELF.gcp_region }}' - resource: {} - bucket~bucket::ansible@minio.server->*->local.machine: - derived_from: bucket + resource: + google_storage_bucket: + bucket: + - name: '{{ SELF.storage_name }}' + location: EU + force_destroy: true + object.storage~object.storage::ansible@minio.server->docker.engine->local.machine: + derived_from: object.storage metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project interfaces: Standard: operations: @@ -1929,32 +3068,158 @@ node_types: operation_host: ORCHESTRATOR inputs: playbook: - q: [] + q: + - name: create bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' delete: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: - q: [] - bucket~bucket::terraform@minio.server->*->local.machine: - derived_from: bucket + q: + - name: delete policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + object.storage~object.storage::compose@minio.server->docker.engine->local.machine: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.database.compose.yaml.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + services: + job: + container_name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc mb minio/{{ SELF.storage_name }} && mc admin user add minio {{ SELF.storage_user }} {{ SELF.storage_token }} && mc admin policy attach minio readwrite user={{ SELF.storage_user }} + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.database.compose.yaml.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + services: + job: + container_name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc admin policy detach minio readwrite user={{ SELF.storage_user }} && mc admin user rm minio {{ SELF.storage_user }} && mc rm --recursive minio/{{ SELF.storage_name }} + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + object.storage~object.storage::terraform@minio.server->docker.engine->local.machine: + derived_from: object.storage metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project interfaces: Standard: operations: @@ -1967,27 +3232,140 @@ node_types: defaults: inputs: main: - terraform: [] - provider: {} - resource: {} - bucket~bucket::ansible@minio.server->*->remote.machine: - derived_from: bucket + terraform: + - required_providers: + - minio: + source: aminueza/minio + version: 2.5.0 + required_version: '>= 0.14.0' + provider: + minio: + - minio_server: '{{ HOST.application_endpoint }}' + minio_user: '{{ HOST.access_key }}' + minio_password: '{{ HOST.secret_key }}' + resource: + minio_s3_bucket: + bucket: + - bucket: '{{ SELF.storage_name }}' + minio_iam_user: + user: + - name: '{{ SELF.storage_user }}' + secret: '{{ SELF.storage_token }}' + minio_iam_policy: + depends_on: + - minio_s3_bucket.bucket + - minio_iam_user.user + policy: + - name: '{{ SELF.storage_user }}' + policy: '{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*"], "Principal": "{{ SELF.storage_user }}", "Resource": "arn:aws:s3:::*" } ] }' + object.storage~object.storage::ansible@minio.server->docker.engine->remote.machine: + derived_from: object.storage metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: + os_ssh_host: type: string default: - get_input: gcp_region - gcp_project: + eval: .::.requirements::[.name=host]::.target::management_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: delete policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + object.storage~object.storage::compose@minio.server->docker.engine->remote.machine: + derived_from: object.storage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_host: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address interfaces: Standard: operations: @@ -1997,71 +3375,179 @@ node_types: operation_host: ORCHESTRATOR inputs: playbook: - q: [] + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + services: + job: + container_name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc mb minio/{{ SELF.storage_name }} && mc admin user add minio {{ SELF.storage_user }} {{ SELF.storage_token }} && mc admin policy attach minio readwrite user={{ SELF.storage_user }} + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' delete: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: - q: [] - bucket~bucket::terraform@minio.server->*->remote.machine: - derived_from: bucket + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + services: + job: + container_name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc admin policy detach minio readwrite user={{ SELF.storage_user }} && mc admin user rm minio {{ SELF.storage_user }} && mc rm --recursive minio/{{ SELF.storage_name }} + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + object.storage~object.storage::terraform@minio.server->docker.engine->remote.machine: + derived_from: object.storage metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + os_ssh_host: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address interfaces: Standard: operations: configure: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file delete: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file defaults: inputs: main: - terraform: [] - provider: {} - resource: {} - bucket~bucket::ansible@minio.server->kubernetes.cluster: - derived_from: bucket + terraform: + - required_providers: + - minio: + source: aminueza/minio + version: 2.5.0 + ssh: + source: AndrewChubatiuk/ssh + version: 0.2.3 + required_version: '>= 0.14.0' + data: + ssh_tunnel: + mysql: + - remote: + host: '{{ HOST.application_address }}' + port: '{{ HOST.application_port }}' + provider: + minio: + - minio_server: '{{ HOST.application_endpoint }}' + minio_user: '{{ HOST.access_key }}' + minio_password: '{{ HOST.secret_key }}' + ssh: + - auth: + private_key: + content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} + server: + host: '{{ HOST.management_address }}' + port: 22 + user: '{{ SELF.os_ssh_user }}' + resource: + minio_s3_bucket: + bucket: + - bucket: '{{ SELF.storage_name }}' + minio_iam_user: + user: + - name: '{{ SELF.storage_user }}' + secret: '{{ SELF.storage_token }}' + minio_iam_policy: + depends_on: + - minio_s3_bucket.bucket + - minio_iam_user.user + policy: + - name: '{{ SELF.storage_user }}' + policy: '{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*"], "Principal": "{{ SELF.storage_user }}", "Resource": "arn:aws:s3:::*" } ] }' + object.storage~object.storage::ansible@minio.server->kubernetes.cluster: + derived_from: object.storage metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + k8s_host: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - get_input: gcp_project + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file interfaces: Standard: operations: @@ -2071,96 +3557,279 @@ node_types: operation_host: ORCHESTRATOR inputs: playbook: - q: [] + q: + - name: create bucket + block: + - name: forward port + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.cache_name }} {{ HOST.cache_port }}:{{ HOST.cache_port }} + args: + executable: /usr/bin/bash + async: 30 + poll: 0 + - name: create bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + - name: create policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + always: + - name: unforward port + ansible.builtin.shell: pkill -f "port-forward service/{{ HOST.cache_name }}" + args: + executable: /usr/bin/bash delete: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: - q: [] - bucket~bucket::terraform@minio.server->kubernetes.cluster: - derived_from: bucket + q: + - name: delete bucket + block: + - name: forward port + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.cache_name }} {{ HOST.cache_port }}:{{ HOST.cache_port }} + args: + executable: /usr/bin/bash + async: 30 + poll: 0 + - name: delete policy + dubzland.minio.minio_policy: + name: '{{ SELF.user_name }}' + statements: + - effect: Allow + action: s3:* + resource: arn:aws:s3:::* + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete user + dubzland.minio.minio_user: + access_key: '{{ SELF.storage_user }}' + secret_key: '{{ SELF.storage_token }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + - name: delete bucket + dubzland.minio.minio_bucket: + name: '{{ SELF.storage_name }}' + auth: + access_key: '{{ HOST.access_key }}' + secret_key: '{{ HOST.secret_key }}' + url: '{{ HOST.application_endpoint }}' + state: absent + always: + - name: unforward port + ansible.builtin.shell: pkill -f "port-forward service/{{ HOST.cache_name }}" + args: + executable: /usr/bin/bash + object.storage~object.storage::kubernetes@minio.server->kubernetes.cluster: + derived_from: object.storage metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + k8s_host: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - get_input: gcp_project + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file interfaces: Standard: operations: - configure: + create: implementation: - primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.object-storage.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: '{{ job | to_yaml }}' + vars: + job: + apiVersion: batch/v1 + kind: Job + metadata: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + spec: + template: + spec: + restartPolicy: Never + containers: + - name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc mb minio/{{ SELF.storage_name }} && mc admin user add minio {{ SELF.storage_user }} {{ SELF.storage_token }} && mc admin policy attach minio readwrite user={{ SELF.storage_user }} + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.storage_name }}-{{ HOST.cache_name }} + args: + executable: /usr/bin/bash + - name: cleanup + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash delete: implementation: - primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file - defaults: - inputs: - main: - terraform: [] - provider: {} - resource: {} - bucket~bucket#cache.image::ansible@gcp.memorystore: - derived_from: bucket + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.storage_name }}-{{ HOST.cache_name }}.object-storage.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: '{{ job | to_yaml }}' + vars: + job: + apiVersion: batch/v1 + kind: Job + metadata: + name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + spec: + template: + spec: + restartPolicy: Never + containers: + - name: '{{ SELF.storage_name }}-{{ HOST.cache_name }}' + image: minio/mc:{{ ".artifacts::cache_image::file" | eval }} + command: + - /bin/bash + - '-c' + - mc alias set minio {{ HOST.application_endpoint }} {{ HOST.access_key }} {{ HOST.secret_key }} && mc admin policy detach minio readwrite user={{ SELF.storage_user }} && mc admin user rm minio {{ SELF.storage_user }} && mc rm --recursive minio/{{ SELF.storage_name }} + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.storage_name }}-{{ HOST.cache_name }} + args: + executable: /usr/bin/bash + - name: cleanup + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + object.storage~object.storage::terraform@minio.server->kubernetes.cluster: + derived_from: object.storage metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + k8s_host: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - get_input: gcp_project + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file interfaces: Standard: operations: - create: + configure: implementation: - primary: Ansible - operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount - inputs: - playbook: - q: [] + primary: Terraform delete: implementation: - primary: Ansible - operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount - inputs: - playbook: - q: [] + primary: Terraform + defaults: + inputs: + main: + terraform: [] + provider: {} + resource: + terraform_data: + forward_port: + - input: 127.0.0.1:{{ HOST.cache_port }} + provisioner: + local-exec: + command: |- + (nohup kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.cache_name }} {{ HOST.cache_port }}:{{ HOST.cache_port }} > /dev/null 2>&1 &) + sleep 5s + interpreter: + - /bin/bash + - '-c' + unforward_port: + - depends_on: + - minio_iam_policy.policy + provisioner: + local-exec: + command: pkill -f "port-forward service/{{ HOST.cache_name }}" + interpreter: + - /bin/bash + - '-c' + minio_s3_bucket: + bucket: + - bucket: '{{ SELF.storage_name }}' + minio_iam_user: + user: + - name: '{{ SELF.storage_user }}' + secret: '{{ SELF.storage_token }}' + minio_iam_policy: + depends_on: + - minio_s3_bucket.bucket + - minio_iam_user.user + policy: + - name: '{{ SELF.storage_user }}' + policy: '{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*"], "Principal": "{{ SELF.storage_user }}", "Resource": "arn:aws:s3:::*" } ] }' ingress~ingress::ansible@kubernetes.cluster: derived_from: ingress metadata: @@ -2348,6 +4017,118 @@ node_types: selector: app: '{{ SELF.application_name }}' type: LoadBalancer + ingress~ingress::ansible@local.machine: + derived_from: ingress + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::application_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: add apt key + ansible.builtin.apt_key: + url: https://dl.cloudsmith.io/public/caddy/stable/gpg.key + keyring: /usr/share/keyrings/caddy-stable-archive-keyring.gpg + state: present + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/caddy-stable-archive-keyring.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main + filename: caddy-stable + state: present + - name: install package + ansible.builtin.apt: + name: caddy + state: present + update_cache: 'yes' + - name: configure caddy + ansible.builtin.copy: + dest: /etc/caddy/Caddyfile + content: | + :80 { + reverse_proxy localhost:{{ SELF.application_port }} + } + - name: restart caddy + ansible.builtin.systemd: + name: caddy + state: reloaded + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: uninstall package + ansible.builtin.apt: + name: caddy + state: absent + ingress~ingress::terraform@local.machine: + derived_from: ingress + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::application_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_script: + content: | + + #!/usr/bin/bash + set -e + + # Install caddy + apt-get install -y debian-keyring debian-archive-keyring apt-transport-https curl + curl -1sLf https://dl.cloudsmith.io/public/caddy/stable/gpg.key | gpg --dearmor --yes -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg + curl -1sLf https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt | tee /etc/apt/sources.list.d/caddy-stable.list + apt-get update + apt-get install caddy -y + + # Configure caddy + cat < /etc/caddy/Caddyfile + :80 { + reverse_proxy localhost:{{ SELF.application_port }} + } + EOF + + # Restart caddy + systemctl reload caddy + destination: /tmp/install-ingress.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_script + provisioner: + local-exec: + - inline: + - sudo bash /tmp/install-ingress.sh ingress~ingress::ansible@remote.machine: derived_from: ingress metadata: diff --git a/examples/unfurl-technology---shop---plus-maintenance-automated/lib/tosca-vintner-profile-extended.yaml b/examples/unfurl-technology---shop---plus-maintenance-automated/lib/tosca-vintner-profile-extended.yaml index 0e4edf7f26..ea43ed49ee 100644 --- a/examples/unfurl-technology---shop---plus-maintenance-automated/lib/tosca-vintner-profile-extended.yaml +++ b/examples/unfurl-technology---shop---plus-maintenance-automated/lib/tosca-vintner-profile-extended.yaml @@ -487,15 +487,20 @@ node_types: derived_from: service.application metadata: vintner_normative: 'true' + properties: + access_key: + type: string + metadata: + vintner_name: MINIO_ROOT_USER + secret_key: + type: string + metadata: + vintner_name: MINIO_ROOT_PASSWORD redis.server: derived_from: cache metadata: vintner_normative: 'true' properties: - cache_name: - type: string - cache_port: - type: string application_protocol: type: string default: redis @@ -514,6 +519,372 @@ node_types: # ################################################################ + nodejs.runtime~software.application#apt.package::ansible@*->local.machine: + derived_from: nodejs.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + nodejs.runtime~software.application#apt.package::terraform@*->local.machine: + derived_from: nodejs.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-nodejs.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-nodejs.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-nodejs.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-nodejs.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-nodejs.runtime.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-nodejs.runtime.sh + - sudo bash /tmp/configure-nodejs.runtime.sh + - sudo bash /tmp/start-nodejs.runtime.sh + - inline: + - sudo bash /tmp/stop-nodejs.runtime.sh + - sudo bash /tmp/delete-nodejs.runtime.sh + when: destroy nodejs.runtime~software.application#apt.package::ansible@*->remote.machine: derived_from: nodejs.runtime metadata: @@ -646,6 +1017,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -677,6 +1052,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -736,7 +1115,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - nodejs.runtime~software.application#apt.archive::terraform@*->remote.machine: + nodejs.runtime~software.application#apt.package::terraform@*->remote.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' @@ -821,14 +1200,6 @@ node_types: APPLICATION_NAME="{{ SELF.application_name }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -933,20 +1304,12 @@ node_types: - sudo bash /tmp/stop-nodejs.runtime.sh - sudo bash /tmp/delete-nodejs.runtime.sh when: destroy - nodejs.runtime~software.application#tar.archive::ansible@*->remote.machine: + nodejs.runtime~software.application#tar.archive::ansible@*->local.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -961,14 +1324,16 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - name: wait for ssh wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -1010,16 +1375,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1041,16 +1400,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1076,16 +1429,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1111,16 +1458,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -1146,27 +1487,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - nodejs.runtime~software.application#tar.archive::terraform@*->remote.machine: + nodejs.runtime~software.application#tar.archive::terraform@*->local.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1188,143 +1513,151 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-nodejs.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-nodejs.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-nodejs.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-nodejs.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-nodejs.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-nodejs.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-nodejs.runtime.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-nodejs.runtime - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-nodejs.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-nodejs.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-nodejs.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-nodejs.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-nodejs.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-nodejs.runtime.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-nodejs.runtime.sh - sudo bash /tmp/configure-nodejs.runtime.sh @@ -1333,7 +1666,7 @@ node_types: - sudo bash /tmp/stop-nodejs.runtime.sh - sudo bash /tmp/delete-nodejs.runtime.sh when: destroy - nodejs.runtime~software.application#zip.archive::ansible@*->remote.machine: + nodejs.runtime~software.application#tar.archive::ansible@*->remote.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' @@ -1369,26 +1702,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -1553,7 +1883,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - nodejs.runtime~software.application#zip.archive::terraform@*->remote.machine: + nodejs.runtime~software.application#tar.archive::terraform@*->remote.machine: derived_from: nodejs.runtime metadata: vintner_generated: 'true' @@ -1600,9 +1930,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' destination: /tmp/artifact-nodejs.runtime - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e @@ -1616,12 +1946,12 @@ node_types: EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-nodejs.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-nodejs.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -1736,20 +2066,12 @@ node_types: - sudo bash /tmp/stop-nodejs.runtime.sh - sudo bash /tmp/delete-nodejs.runtime.sh when: destroy - python.runtime~software.application#apt.package::ansible@*->remote.machine: - derived_from: python.runtime + nodejs.runtime~software.application#zip.archive::ansible@*->local.machine: + derived_from: nodejs.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -1764,48 +2086,39 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: run setup script - ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - args: - executable: /bin/bash - when: '".artifacts::apt_package::script" | eval != ""' - - name: add apt key - ansible.builtin.apt_key: - url: '{{ ".artifacts::apt_package::key" | eval }}' - keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - state: present - when: '".artifacts::apt_package::key" | eval != ""' - - name: add apt repository - ansible.builtin.apt_repository: - repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} - filename: '{{ ".artifacts::apt_package::repository" | eval }}' - state: present - when: '".artifacts::apt_package::source" | eval != ""' - - name: update apt cache + - name: install operational dependencies ansible.builtin.apt: + name: unzip update_cache: 'yes' - - name: install dependencies - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' - state: present - when: '".artifacts::apt_package::dependencies" | eval != ""' - - name: install package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: present - environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -1822,21 +2135,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -1853,21 +2158,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -1884,21 +2185,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -1915,21 +2212,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -1950,31 +2239,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - - name: uninstall package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - python.runtime~software.application#apt.archive::terraform@*->remote.machine: - derived_from: python.runtime + nodejs.runtime~software.application#zip.archive::terraform@*->local.machine: + derived_from: nodejs.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -1996,263 +2265,261 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-nodejs.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-nodejs.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-nodejs.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-nodejs.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-nodejs.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-nodejs.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-nodejs.runtime.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - content: | - #!/usr/bin/bash - set -e - - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi - - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi - - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then - echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} - fi + local-exec: + - inline: + - sudo bash /tmp/create-nodejs.runtime.sh + - sudo bash /tmp/configure-nodejs.runtime.sh + - sudo bash /tmp/start-nodejs.runtime.sh + - inline: + - sudo bash /tmp/stop-nodejs.runtime.sh + - sudo bash /tmp/delete-nodejs.runtime.sh + when: destroy + nodejs.runtime~software.application#zip.archive::ansible@*->remote.machine: + derived_from: nodejs.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e - # Update apt cache - apt-get update -y - - # Install dependencies - if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then - apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y - fi - - # Install package - {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-python.runtime {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-python.runtime.sh - remote-exec: - - inline: - - sudo bash /tmp/create-python.runtime.sh - - sudo bash /tmp/configure-python.runtime.sh - - sudo bash /tmp/start-python.runtime.sh - - inline: - - sudo bash /tmp/stop-python.runtime.sh - - sudo bash /tmp/delete-python.runtime.sh - when: destroy - python.runtime~software.application#tar.archive::ansible@*->remote.machine: - derived_from: python.runtime - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - application_directory: - type: string - default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name - interfaces: - Standard: - operations: - create: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") - - name: extract deployment artifact from URL in application directory - ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: '' - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/create.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - mode: '0755' - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/create.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - configure: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/configure.sh' - content: |- - #!/usr/bin/bash - set -e + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} mode: '0755' @@ -2372,8 +2639,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - python.runtime~software.application#tar.archive::terraform@*->remote.machine: - derived_from: python.runtime + nodejs.runtime~software.application#zip.archive::terraform@*->remote.machine: + derived_from: nodejs.runtime metadata: vintner_generated: 'true' properties: @@ -2419,9 +2686,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-python.runtime - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-nodejs.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e @@ -2431,16 +2698,16 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - + APPLICATION_NAME="{{ SELF.application_name }}" EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-python.runtime {{ ".artifacts::tar_archive::file" | eval }} + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-nodejs.runtime {{ ".artifacts::zip_archive::file" | eval }} fi # Extract deployment artifact - tar -xzf /tmp/artifact-python.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + unzip /tmp/artifact-nodejs.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -2458,7 +2725,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-python.runtime.sh + destination: /tmp/create-nodejs.runtime.sh - content: | #!/usr/bin/bash set -e @@ -2476,7 +2743,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-python.runtime.sh + destination: /tmp/configure-nodejs.runtime.sh - content: | #!/usr/bin/bash set -e @@ -2500,7 +2767,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-python.runtime.sh + destination: /tmp/start-nodejs.runtime.sh - content: | #!/usr/bin/bash set -e @@ -2524,7 +2791,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-python.runtime.sh + destination: /tmp/stop-nodejs.runtime.sh - content: | #!/usr/bin/bash set -e @@ -2545,30 +2812,22 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-python.runtime.sh + destination: /tmp/delete-nodejs.runtime.sh remote-exec: - inline: - - sudo bash /tmp/create-python.runtime.sh - - sudo bash /tmp/configure-python.runtime.sh - - sudo bash /tmp/start-python.runtime.sh + - sudo bash /tmp/create-nodejs.runtime.sh + - sudo bash /tmp/configure-nodejs.runtime.sh + - sudo bash /tmp/start-nodejs.runtime.sh - inline: - - sudo bash /tmp/stop-python.runtime.sh - - sudo bash /tmp/delete-python.runtime.sh + - sudo bash /tmp/stop-nodejs.runtime.sh + - sudo bash /tmp/delete-nodejs.runtime.sh when: destroy - python.runtime~software.application#zip.archive::ansible@*->remote.machine: + python.runtime~software.application#apt.package::ansible@*->local.machine: derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -2583,42 +2842,44 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: install operational dependencies + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache ansible.builtin.apt: - name: unzip update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -2635,21 +2896,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -2666,21 +2919,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -2701,21 +2946,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "stop" missing @@ -2736,21 +2973,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -2771,27 +3000,15 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - python.runtime~software.application#zip.archive::terraform@*->remote.machine: + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + python.runtime~software.application#apt.package::terraform@*->local.machine: derived_from: python.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -2813,143 +3030,156 @@ node_types: inputs: main: resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-python.runtime - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-python.runtime {{ ".artifacts::zip_archive::file" | eval }} - fi - - # Extract deployment artifact - unzip /tmp/artifact-python.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e + # Update apt cache + apt-get update -y - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi + # Create application directory + mkdir -p {{ SELF.application_directory }} - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e + # Create application environment + cat < {{ SELF.application_directory }}/.env - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh + EOF>> - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-python.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-python.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-python.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-python.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-python.runtime.sh - - content: | - #!/usr/bin/bash - set -e + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh + # Delete application directory + rm -rf "{{ SELF.application_directory }}" - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-python.runtime.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-python.runtime.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: - inline: - sudo bash /tmp/create-python.runtime.sh - sudo bash /tmp/configure-python.runtime.sh @@ -2958,8 +3188,8 @@ node_types: - sudo bash /tmp/stop-python.runtime.sh - sudo bash /tmp/delete-python.runtime.sh when: destroy - java.runtime~software.application#apt.package::ansible@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#apt.package::ansible@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -3090,6 +3320,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -3121,6 +3355,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -3180,8 +3418,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - java.runtime~software.application#apt.archive::terraform@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#apt.package::terraform@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: @@ -3262,16 +3500,8 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-java.runtime {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined + EOF>> # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -3289,7 +3519,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-java.runtime.sh + destination: /tmp/create-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -3307,7 +3537,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-java.runtime.sh + destination: /tmp/configure-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -3325,7 +3555,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-java.runtime.sh + destination: /tmp/start-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -3343,7 +3573,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-java.runtime.sh + destination: /tmp/stop-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -3367,30 +3597,22 @@ node_types: # Uninstall package apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-java.runtime.sh + destination: /tmp/delete-python.runtime.sh remote-exec: - inline: - - sudo bash /tmp/create-java.runtime.sh - - sudo bash /tmp/configure-java.runtime.sh - - sudo bash /tmp/start-java.runtime.sh + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh - inline: - - sudo bash /tmp/stop-java.runtime.sh - - sudo bash /tmp/delete-java.runtime.sh + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh when: destroy - java.runtime~software.application#tar.archive::ansible@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#tar.archive::ansible@*->local.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -3405,14 +3627,16 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - name: wait for ssh wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' @@ -3437,7 +3661,7 @@ node_types: - name: create .env file ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' - content: APPLICATION_NAME="{{ SELF.application_name }}" + content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -3454,16 +3678,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -3485,16 +3703,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -3520,16 +3732,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -3555,16 +3761,10 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: @@ -3590,27 +3790,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - java.runtime~software.application#tar.archive::terraform@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#tar.archive::terraform@*->local.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -3632,153 +3816,161 @@ node_types: inputs: main: resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-java.runtime - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-java.runtime {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-java.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-java.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-java.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-python.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-java.runtime.sh - - content: | - #!/usr/bin/bash - set -e + # Create application directory + mkdir -p {{ SELF.application_directory }} - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi + # Create application environment + cat < {{ SELF.application_directory }}/.env - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e + EOF>> - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-python.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-java.runtime.sh - - content: | - #!/usr/bin/bash - set -e + # Extract deployment artifact + tar -xzf /tmp/artifact-python.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-java.runtime.sh - remote-exec: - - inline: - - sudo bash /tmp/create-java.runtime.sh - - sudo bash /tmp/configure-java.runtime.sh - - sudo bash /tmp/start-java.runtime.sh + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-python.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-python.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-python.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-python.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-python.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - - sudo bash /tmp/stop-java.runtime.sh - - sudo bash /tmp/delete-java.runtime.sh + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh + - inline: + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh when: destroy - java.runtime~software.application#zip.archive::ansible@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#tar.archive::ansible@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -3813,26 +4005,23 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies - ansible.builtin.apt: - name: unzip - update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::tar_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -3840,7 +4029,7 @@ node_types: - name: create .env file ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' - content: APPLICATION_NAME="{{ SELF.application_name }}" + content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -3997,8 +4186,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - java.runtime~software.application#zip.archive::terraform@*->remote.machine: - derived_from: java.runtime + python.runtime~software.application#tar.archive::terraform@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: @@ -4044,9 +4233,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-java.runtime - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-python.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e @@ -4056,16 +4245,16 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-java.runtime {{ ".artifacts::zip_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-python.runtime {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - unzip /tmp/artifact-java.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + tar -xzf /tmp/artifact-python.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -4083,7 +4272,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-java.runtime.sh + destination: /tmp/create-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4101,7 +4290,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-java.runtime.sh + destination: /tmp/configure-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4125,7 +4314,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-java.runtime.sh + destination: /tmp/start-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4149,7 +4338,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-java.runtime.sh + destination: /tmp/stop-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4170,30 +4359,22 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-java.runtime.sh + destination: /tmp/delete-python.runtime.sh remote-exec: - inline: - - sudo bash /tmp/create-java.runtime.sh - - sudo bash /tmp/configure-java.runtime.sh - - sudo bash /tmp/start-java.runtime.sh + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh - inline: - - sudo bash /tmp/stop-java.runtime.sh - - sudo bash /tmp/delete-java.runtime.sh + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh when: destroy - dotnet.runtime~software.application#apt.package::ansible@*->remote.machine: - derived_from: dotnet.runtime + python.runtime~software.application#zip.archive::ansible@*->local.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -4208,48 +4389,39 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: run setup script - ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - args: - executable: /bin/bash - when: '".artifacts::apt_package::script" | eval != ""' - - name: add apt key - ansible.builtin.apt_key: - url: '{{ ".artifacts::apt_package::key" | eval }}' - keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - state: present - when: '".artifacts::apt_package::key" | eval != ""' - - name: add apt repository - ansible.builtin.apt_repository: - repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} - filename: '{{ ".artifacts::apt_package::repository" | eval }}' - state: present - when: '".artifacts::apt_package::source" | eval != ""' - - name: update apt cache + - name: install operational dependencies ansible.builtin.apt: + name: unzip update_cache: 'yes' - - name: install dependencies - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' - state: present - when: '".artifacts::apt_package::dependencies" | eval != ""' - - name: install package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: present - environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -4266,21 +4438,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -4297,21 +4461,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -4328,21 +4488,17 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -4359,21 +4515,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -4394,31 +4542,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - - name: uninstall package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - dotnet.runtime~software.application#apt.archive::terraform@*->remote.machine: - derived_from: dotnet.runtime + python.runtime~software.application#zip.archive::terraform@*->local.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -4440,167 +4568,161 @@ node_types: inputs: main: resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - content: | - #!/usr/bin/bash - set -e - - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi - - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi - - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then - echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} - fi + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-python.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e - # Update apt cache - apt-get update -y + # Create application directory + mkdir -p {{ SELF.application_directory }} - # Install dependencies - if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then - apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y - fi + # Create application environment + cat < {{ SELF.application_directory }}/.env - # Install package - {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + EOF>> - # Create application directory - mkdir -p {{ SELF.application_directory }} + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-python.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> + # Extract deployment artifact + unzip /tmp/artifact-python.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::apt_archive::file" | eval }} - fi + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner - # Extract deployment artifact - undefined + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-dotnet.runtime.sh - remote-exec: + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-python.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-python.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-python.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-python.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-python.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - - sudo bash /tmp/create-dotnet.runtime.sh - - sudo bash /tmp/configure-dotnet.runtime.sh - - sudo bash /tmp/start-dotnet.runtime.sh + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh - inline: - - sudo bash /tmp/stop-dotnet.runtime.sh - - sudo bash /tmp/delete-dotnet.runtime.sh + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh when: destroy - dotnet.runtime~software.application#tar.archive::ansible@*->remote.machine: - derived_from: dotnet.runtime + python.runtime~software.application#zip.archive::ansible@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -4635,23 +4757,27 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -4659,7 +4785,7 @@ node_types: - name: create .env file ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' - content: APPLICATION_NAME="{{ SELF.application_name }}" + content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -4816,8 +4942,8 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - dotnet.runtime~software.application#tar.archive::terraform@*->remote.machine: - derived_from: dotnet.runtime + python.runtime~software.application#zip.archive::terraform@*->remote.machine: + derived_from: python.runtime metadata: vintner_generated: 'true' properties: @@ -4863,9 +4989,9 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-dotnet.runtime - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-python.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e @@ -4875,16 +5001,16 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::tar_archive::file" | eval }} + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-python.runtime {{ ".artifacts::zip_archive::file" | eval }} fi # Extract deployment artifact - tar -xzf /tmp/artifact-dotnet.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + unzip /tmp/artifact-python.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -4902,7 +5028,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-dotnet.runtime.sh + destination: /tmp/create-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4920,7 +5046,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-dotnet.runtime.sh + destination: /tmp/configure-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4944,7 +5070,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-dotnet.runtime.sh + destination: /tmp/start-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4968,7 +5094,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-dotnet.runtime.sh + destination: /tmp/stop-python.runtime.sh - content: | #!/usr/bin/bash set -e @@ -4989,30 +5115,22 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-dotnet.runtime.sh + destination: /tmp/delete-python.runtime.sh remote-exec: - inline: - - sudo bash /tmp/create-dotnet.runtime.sh - - sudo bash /tmp/configure-dotnet.runtime.sh - - sudo bash /tmp/start-dotnet.runtime.sh + - sudo bash /tmp/create-python.runtime.sh + - sudo bash /tmp/configure-python.runtime.sh + - sudo bash /tmp/start-python.runtime.sh - inline: - - sudo bash /tmp/stop-dotnet.runtime.sh - - sudo bash /tmp/delete-dotnet.runtime.sh + - sudo bash /tmp/stop-python.runtime.sh + - sudo bash /tmp/delete-python.runtime.sh when: destroy - dotnet.runtime~software.application#zip.archive::ansible@*->remote.machine: - derived_from: dotnet.runtime + java.runtime~software.application#apt.package::ansible@*->local.machine: + derived_from: java.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -5027,42 +5145,44 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: install operational dependencies + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache ansible.builtin.apt: - name: unzip update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: APPLICATION_NAME="{{ SELF.application_name }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -5079,21 +5199,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -5110,21 +5222,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -5145,21 +5249,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "stop" missing @@ -5180,21 +5276,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -5215,27 +5303,15 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - dotnet.runtime~software.application#zip.archive::terraform@*->remote.machine: - derived_from: dotnet.runtime + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + java.runtime~software.application#apt.package::terraform@*->local.machine: + derived_from: java.runtime metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -5257,222 +5333,5063 @@ node_types: inputs: main: resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-dotnet.runtime - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::zip_archive::file" | eval }} - fi - - # Extract deployment artifact - unzip /tmp/artifact-dotnet.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-java.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-java.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-java.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-java.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-dotnet.runtime.sh - - content: | - #!/usr/bin/bash - set -e + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh + # Delete application directory + rm -rf "{{ SELF.application_directory }}" - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-dotnet.runtime.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-java.runtime.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: - inline: - - sudo bash /tmp/create-dotnet.runtime.sh - - sudo bash /tmp/configure-dotnet.runtime.sh - - sudo bash /tmp/start-dotnet.runtime.sh + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh - inline: - - sudo bash /tmp/stop-dotnet.runtime.sh - - sudo bash /tmp/delete-dotnet.runtime.sh + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh when: destroy - gcp.cloudrun~gcp.service::ansible: - derived_from: gcp.cloudrun + java.runtime~software.application#apt.package::ansible@*->remote.machine: + derived_from: java.runtime metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.cloudrun~gcp.service::terraform: - derived_from: gcp.cloudrun - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform - delete: - implementation: - primary: Terraform - defaults: - inputs: - main: - terraform: - - required_providers: - - google: - source: hashicorp/google + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + java.runtime~software.application#apt.package::terraform@*->remote.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-java.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + java.runtime~software.application#tar.archive::ansible@*->local.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + java.runtime~software.application#tar.archive::terraform@*->local.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-java.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-java.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-java.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-java.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-java.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-java.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-java.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-java.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + java.runtime~software.application#tar.archive::ansible@*->remote.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + java.runtime~software.application#tar.archive::terraform@*->remote.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-java.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-java.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-java.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-java.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + java.runtime~software.application#zip.archive::ansible@*->local.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + java.runtime~software.application#zip.archive::terraform@*->local.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-java.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-java.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-java.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-java.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-java.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-java.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-java.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-java.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + java.runtime~software.application#zip.archive::ansible@*->remote.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + java.runtime~software.application#zip.archive::terraform@*->remote.machine: + derived_from: java.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-java.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-java.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-java.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-java.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-java.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-java.runtime.sh + - sudo bash /tmp/configure-java.runtime.sh + - sudo bash /tmp/start-java.runtime.sh + - inline: + - sudo bash /tmp/stop-java.runtime.sh + - sudo bash /tmp/delete-java.runtime.sh + when: destroy + dotnet.runtime~software.application#apt.package::ansible@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + dotnet.runtime~software.application#apt.package::terraform@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-dotnet.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-dotnet.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-dotnet.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-dotnet.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-dotnet.runtime.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#apt.package::ansible@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + dotnet.runtime~software.application#apt.package::terraform@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-dotnet.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#tar.archive::ansible@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + dotnet.runtime~software.application#tar.archive::terraform@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-dotnet.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-dotnet.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-dotnet.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-dotnet.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-dotnet.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-dotnet.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-dotnet.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#tar.archive::ansible@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + dotnet.runtime~software.application#tar.archive::terraform@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-dotnet.runtime + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-dotnet.runtime -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-dotnet.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#zip.archive::ansible@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + dotnet.runtime~software.application#zip.archive::terraform@*->local.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-dotnet.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-dotnet.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-dotnet.runtime.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-dotnet.runtime.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-dotnet.runtime.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-dotnet.runtime.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-dotnet.runtime.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + dotnet.runtime~software.application#zip.archive::ansible@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: APPLICATION_NAME="{{ SELF.application_name }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + dotnet.runtime~software.application#zip.archive::terraform@*->remote.machine: + derived_from: dotnet.runtime + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-dotnet.runtime + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-dotnet.runtime {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-dotnet.runtime -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-dotnet.runtime.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-dotnet.runtime.sh + remote-exec: + - inline: + - sudo bash /tmp/create-dotnet.runtime.sh + - sudo bash /tmp/configure-dotnet.runtime.sh + - sudo bash /tmp/start-dotnet.runtime.sh + - inline: + - sudo bash /tmp/stop-dotnet.runtime.sh + - sudo bash /tmp/delete-dotnet.runtime.sh + when: destroy + gcp.cloudrun~gcp.service::ansible: + derived_from: gcp.cloudrun + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.cloudrun~gcp.service::terraform: + derived_from: gcp.cloudrun + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.cloudsql~gcp.service::ansible: + derived_from: gcp.cloudsql + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.cloudsql~gcp.service::terraform: + derived_from: gcp.cloudsql + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.appengine~gcp.service::ansible: + derived_from: gcp.appengine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.appengine~gcp.service::terraform: + derived_from: gcp.appengine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.appenginereporting~gcp.service::ansible: + derived_from: gcp.appenginereporting + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.appenginereporting~gcp.service::terraform: + derived_from: gcp.appenginereporting + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.cloudbuild~gcp.service::ansible: + derived_from: gcp.cloudbuild + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.cloudbuild~gcp.service::terraform: + derived_from: gcp.cloudbuild + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.kubernetesengine~gcp.service::ansible: + derived_from: gcp.kubernetesengine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.kubernetesengine~gcp.service::terraform: + derived_from: gcp.kubernetesengine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.cloudstorage~gcp.service::ansible: + derived_from: gcp.cloudstorage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.cloudstorage~gcp.service::terraform: + derived_from: gcp.cloudstorage + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 4.67.0 + required_version: '>= 0.14.0' + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + resource: + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + gcp.memorystore~gcp.service::ansible: + derived_from: gcp.memorystore + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: enable service + google.cloud.gcp_serviceusage_service: + name: '{{ SELF.gcp_service }}' + project: '{{ SELF.gcp_project }}' + delete: exit 0 + gcp.memorystore~gcp.service::terraform: + derived_from: gcp.memorystore + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google version: 4.67.0 required_version: '>= 0.14.0' provider: @@ -5481,29 +10398,2714 @@ node_types: project: '{{ SELF.gcp_project }}' region: '{{ SELF.gcp_region }}' resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.cloudsql~gcp.service::ansible: - derived_from: gcp.cloudsql + google_project_service: + cloud_sql_admin: + - disable_on_destroy: false + project: '{{ SELF.gcp_project }}' + service: '{{ SELF.gcp_service }}' + docker.engine~docker.engine::ansible@local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install docker + ansible.builtin.shell: curl -sSL https://get.docker.com | sh + args: + executable: /usr/bin/bash + - name: update service + ansible.builtin.copy: + dest: /lib/systemd/system/docker.service + content: | + [Unit] + Description=Docker Application Container Engine + Documentation=https://docs.docker.com + After=network-online.target docker.socket firewalld.service containerd.service time-set.target + Wants=network-online.target containerd.service + Requires=docker.socket + + [Service] + Type=notify + ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock + ExecReload=/bin/kill -s HUP $MAINPID + TimeoutStartSec=0 + RestartSec=2 + Restart=always + StartLimitBurst=3 + StartLimitInterval=60s + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + Delegate=yes + KillMode=process + OOMScoreAdjust=-500 + + [Install] + WantedBy=multi-user.target + - name: restart service + ansible.builtin.systemd: + name: docker.service + state: restarted + enabled: 'yes' + daemon_reload: 'yes' + - name: add docker group + ansible.builtin.group: + name: docker + - name: add user to docker group + ansible.builtin.user: + name: '{{ SELF.os_ssh_user }}' + groups: docker + append: 'yes' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: delete docker packages + ansible.builtin.apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + - docker-ce-rootless-extras + state: absent + purge: 'true' + autoremove: 'true' + - name: delete docker directories + ansible.builtin.file: + name: '{{ item }}' + state: absent + loop: + - /var/lib/docker + - /var/lib/containerd + docker.engine~docker.engine::terraform@local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - mysql: + source: hashicorp/local + version: 2.5.1 + required_version: '>= 0.14.0' + resource: + local_file: + tmp_service: + content: | + [Unit] + Description=Docker Application Container Engine + Documentation=https://docs.docker.com + After=network-online.target docker.socket firewalld.service containerd.service time-set.target + Wants=network-online.target containerd.service + Requires=docker.socket + + [Service] + Type=notify + ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock + ExecReload=/bin/kill -s HUP $MAINPID + TimeoutStartSec=0 + RestartSec=2 + Restart=always + StartLimitBurst=3 + StartLimitInterval=60s + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + Delegate=yes + KillMode=process + OOMScoreAdjust=-500 + + [Install] + WantedBy=multi-user.target + filename: /tmp/docker.service + terraform_data: + local: + - depends_on: local_file.tmp_service + provisioner: + local-exec: + - inline: + - curl -sSL https://get.docker.com | sudo sh + - sudo groupadd -f docker + - sudo usermod -aG docker {{ SELF.os_ssh_user }} + - sleep 10s + - cat /tmp/docker.service | sudo tee /lib/systemd/system/docker.service + - sudo systemctl daemon-reload + - sudo systemctl restart docker.service + - inline: + - sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras -y + - sudo rm -rf /var/lib/docker + - sudo rm -rf /var/lib/containerd + when: destroy + docker.engine~docker.engine::ansible@remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install docker + ansible.builtin.shell: curl -sSL https://get.docker.com | sh + args: + executable: /usr/bin/bash + - name: update service + ansible.builtin.copy: + dest: /lib/systemd/system/docker.service + content: | + [Unit] + Description=Docker Application Container Engine + Documentation=https://docs.docker.com + After=network-online.target docker.socket firewalld.service containerd.service time-set.target + Wants=network-online.target containerd.service + Requires=docker.socket + + [Service] + Type=notify + ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock + ExecReload=/bin/kill -s HUP $MAINPID + TimeoutStartSec=0 + RestartSec=2 + Restart=always + StartLimitBurst=3 + StartLimitInterval=60s + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + Delegate=yes + KillMode=process + OOMScoreAdjust=-500 + + [Install] + WantedBy=multi-user.target + - name: restart service + ansible.builtin.systemd: + name: docker.service + state: restarted + enabled: 'yes' + daemon_reload: 'yes' + - name: add docker group + ansible.builtin.group: + name: docker + - name: add user to docker group + ansible.builtin.user: + name: '{{ SELF.os_ssh_user }}' + groups: docker + append: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: delete docker packages + ansible.builtin.apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + - docker-ce-rootless-extras + state: absent + purge: 'true' + autoremove: 'true' + - name: delete docker directories + ansible.builtin.file: + name: '{{ item }}' + state: absent + loop: + - /var/lib/docker + - /var/lib/containerd + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + docker.engine~docker.engine::terraform@remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_version: '>= 0.14.0' + resource: + terraform_data: + docker: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + [Unit] + Description=Docker Application Container Engine + Documentation=https://docs.docker.com + After=network-online.target docker.socket firewalld.service containerd.service time-set.target + Wants=network-online.target containerd.service + Requires=docker.socket + + [Service] + Type=notify + ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock + ExecReload=/bin/kill -s HUP $MAINPID + TimeoutStartSec=0 + RestartSec=2 + Restart=always + StartLimitBurst=3 + StartLimitInterval=60s + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + Delegate=yes + KillMode=process + OOMScoreAdjust=-500 + + [Install] + WantedBy=multi-user.target + destination: /tmp/docker.service + remote-exec: + - inline: + - curl -sSL https://get.docker.com | sudo sh + - sudo groupadd -f docker + - sudo usermod -aG docker {{ SELF.os_ssh_user }} + - sleep 10s + - cat /tmp/docker.service | sudo tee /lib/systemd/system/docker.service + - sudo systemctl daemon-reload + - sudo systemctl restart docker.service + - inline: + - sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras -y + - sudo rm -rf /var/lib/docker + - sudo rm -rf /var/lib/containerd + when: destroy + docker.engine~software.application#apt.package::ansible@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + docker.engine~software.application#apt.package::terraform@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-docker.engine.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-docker.engine.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-docker.engine.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-docker.engine.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-docker.engine.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#apt.package::ansible@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + docker.engine~software.application#apt.package::terraform@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-docker.engine.sh + remote-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#tar.archive::ansible@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + docker.engine~software.application#tar.archive::terraform@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-docker.engine + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-docker.engine {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-docker.engine -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-docker.engine.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-docker.engine.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-docker.engine.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-docker.engine.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-docker.engine.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#tar.archive::ansible@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + docker.engine~software.application#tar.archive::terraform@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-docker.engine + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-docker.engine {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-docker.engine -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-docker.engine.sh + remote-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#zip.archive::ansible@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + docker.engine~software.application#zip.archive::terraform@*->local.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-docker.engine + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-docker.engine {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-docker.engine -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-docker.engine.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-docker.engine.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-docker.engine.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-docker.engine.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-docker.engine.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + docker.engine~software.application#zip.archive::ansible@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + docker.engine~software.application#zip.archive::terraform@*->remote.machine: + derived_from: docker.engine + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-docker.engine + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_NAME="{{ SELF.application_name }}" + _HOSTING="{{ SELF._hosting }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-docker.engine {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-docker.engine -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-docker.engine.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-docker.engine.sh + remote-exec: + - inline: + - sudo bash /tmp/create-docker.engine.sh + - sudo bash /tmp/configure-docker.engine.sh + - sudo bash /tmp/start-docker.engine.sh + - inline: + - sudo bash /tmp/stop-docker.engine.sh + - sudo bash /tmp/delete-docker.engine.sh + when: destroy + mysql.dbms~mysql.dbms#dbms.image::ansible@docker.engine->local.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - gcp_service_account_file: + attributes: + application_address: type: string - default: - get_input: gcp_service_account_file - gcp_region: + default: 127.0.0.1 + application_port: type: string - default: - get_input: gcp_region - gcp_project: + default: 3306 + management_address: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 interfaces: Standard: operations: @@ -5511,83 +13113,53 @@ node_types: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.cloudsql~gcp.service::terraform: - derived_from: gcp.cloudsql - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform + - name: start container + community.docker.docker_container: + name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + env: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password | string }}' delete: implementation: - primary: Terraform - defaults: - inputs: - main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - required_version: '>= 0.14.0' - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.appengine~gcp.service::ansible: - derived_from: gcp.appengine + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: delete container + community.docker.docker_container: + name: '{{ SELF.dbms_name }}' + state: absent + mysql.dbms~mysql.dbms#dbms.image::compose@docker.engine->local.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: + attributes: + application_address: type: string - default: - get_input: gcp_region - gcp_project: + default: 127.0.0.1 + application_port: + type: integer + default: 3306 + management_address: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address interfaces: Standard: operations: @@ -5595,120 +13167,89 @@ node_types: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.appengine~gcp.service::terraform: - derived_from: gcp.appengine - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform - delete: - implementation: - primary: Terraform - defaults: - inputs: - main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - required_version: '>= 0.14.0' - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.appenginereporting~gcp.service::ansible: - derived_from: gcp.appenginereporting - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project - interfaces: - Standard: - operations: - create: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.dbms_name }}' + services: + application: + container_name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + environment: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + delete: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.appenginereporting~gcp.service::terraform: - derived_from: gcp.appenginereporting + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.dbms_name }}' + services: + application: + container_name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + environment: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + mysql.dbms~mysql.dbms#dbms.image::terraform@docker.engine->local.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: + attributes: + application_address: type: string - default: - get_input: gcp_region - gcp_project: + default: 127.0.0.1 + application_port: + type: integer + default: 3306 + management_address: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address interfaces: Standard: operations: @@ -5723,123 +13264,126 @@ node_types: main: terraform: - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - required_version: '>= 0.14.0' + - docker: + source: kreuzwerker/docker + version: 3.0.2 provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' + docker: + - host: unix:///var/run/docker.sock resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.cloudbuild~gcp.service::ansible: - derived_from: gcp.cloudbuild + docker_container: + application: + - name: '{{ SELF.dbms_name }}' + image: ${docker_image.image.image_id} + network_mode: host + env: + - MYSQL_ROOT_PASSWORD={{ SELF.dbms_password }} + docker_image: + image: + - name: mysql:{{ ".artifacts::dbms_image::file" | eval }} + mysql.dbms~mysql.dbms#dbms.image::ansible@docker.engine->remote.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + attributes: + application_address: + type: string + default: 127.0.0.1 + application_port: + type: string + default: 3306 + management_address: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.cloudbuild~gcp.service::terraform: - derived_from: gcp.cloudbuild - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform + - name: wait for ssh + wait_for_connection: + - name: start container + community.docker.docker_container: + name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + env: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password | string }}' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' delete: implementation: - primary: Terraform - defaults: - inputs: - main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - required_version: '>= 0.14.0' - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.kubernetesengine~gcp.service::ansible: - derived_from: gcp.kubernetesengine + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.dbms~mysql.dbms#dbms.image::compose@docker.engine->remote.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_host: type: string default: - get_input: gcp_service_account_file - gcp_region: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: type: string - default: - get_input: gcp_region - gcp_project: + default: 127.0.0.1 + application_port: + type: integer + default: 3306 + management_address: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address interfaces: Standard: operations: @@ -5847,36 +13391,106 @@ node_types: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.kubernetesengine~gcp.service::terraform: - derived_from: gcp.kubernetesengine + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.dbms_name }}' + services: + application: + container_name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + environment: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.dbms_name }}' + services: + application: + container_name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + environment: + MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + mysql.dbms~mysql.dbms#dbms.image::terraform@docker.engine->remote.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + os_ssh_host: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: 3306 + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address interfaces: Standard: operations: @@ -5891,23 +13505,37 @@ node_types: main: terraform: - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 + - docker: + source: kreuzwerker/docker + version: 3.0.2 required_version: '>= 0.14.0' provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' + docker: + - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 + ssh_opts: + - '-i' + - '{{ SELF.os_ssh_key_file }}' + - '-o' + - IdentitiesOnly=yes + - '-o' + - BatchMode=yes + - '-o' + - UserKnownHostsFile=/dev/null + - '-o' + - StrictHostKeyChecking=no resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.cloudstorage~gcp.service::ansible: - derived_from: gcp.cloudstorage + docker_container: + application: + - name: '{{ SELF.dbms_name }}' + image: ${docker_image.image.image_id} + network_mode: host + env: + - MYSQL_ROOT_PASSWORD={{ SELF.dbms_password }} + docker_image: + image: + - name: mysql:{{ ".artifacts::dbms_image::file" | eval }} + mysql.dbms~mysql.dbms#dbms.image::ansible@gcp.cloudsql: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -5924,6 +13552,21 @@ node_types: type: string default: get_input: gcp_project + dbms_ssl_mode: + type: string + default: Preferred + attributes: + application_port: + type: string + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port interfaces: Standard: operations: @@ -5938,13 +13581,55 @@ node_types: inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' + - name: create a instance + register: instance_info + google.cloud.gcp_sql_instance: + name: '{{ SELF.dbms_name }}' + database_version: MYSQL_{{ ".artifacts::dbms_image::file" | eval | replace(".", "_") }} + settings: + tier: db-f1-micro + availability_type: REGIONAL + backup_configuration: + binary_log_enabled: true + enabled: true + ip_configuration: + authorized_networks: + - value: 0.0.0.0/0 + region: '{{ SELF.gcp_region }}' project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.cloudstorage~gcp.service::terraform: - derived_from: gcp.cloudstorage + - name: set root password + google.cloud.gcp_sql_user: + name: root + host: '%' + password: '{{ SELF.dbms_password }}' + instance: '{{ instance_info }}' + project: '{{ SELF.gcp_project }}' + - name: aet attributes + set_fact: + application_address: '{{ instance_info.ipAddresses[0].ipAddress | trim }}' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address }}' + outputs: + application_address: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: Activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: Delete Instance + ansible.builtin.shell: gcloud sql instances delete {{ SELF.dbms_name }} --quiet + args: + executable: /bin/bash + mysql.dbms~mysql.dbms#dbms.image::terraform@gcp.cloudsql: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -5961,6 +13646,21 @@ node_types: type: string default: get_input: gcp_project + dbms_ssl_mode: + type: string + default: Preferred + attributes: + application_port: + type: string + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port interfaces: Standard: operations: @@ -5971,6 +13671,8 @@ node_types: implementation: primary: Terraform defaults: + outputs: + application_address: application_address inputs: main: terraform: @@ -5978,36 +13680,76 @@ node_types: - google: source: hashicorp/google version: 4.67.0 - required_version: '>= 0.14.0' provider: google: - credentials: '{{ SELF.gcp_service_account_file }}' project: '{{ SELF.gcp_project }}' region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: ${google_sql_database_instance.dbms.public_ip_address} resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - gcp.memorystore~gcp.service::ansible: - derived_from: gcp.memorystore + google_sql_database_instance: + dbms: + - database_version: MYSQL_{{ ".artifacts::dbms_image::file" | eval | replace(".", "_") }} + deletion_protection: false + name: '{{ SELF.dbms_name }}' + root_password: '{{ SELF.dbms_password }}' + settings: + - availability_type: REGIONAL + backup_configuration: + - binary_log_enabled: true + enabled: true + ip_configuration: + - authorized_networks: + - name: public + value: 0.0.0.0/0 + ipv4_enabled: true + tier: db-f1-micro + google_sql_user: + user: + - host: '%' + instance: ${google_sql_database_instance.dbms.name} + name: root + password: ${google_sql_database_instance.dbms.root_password} + mysql.dbms~mysql.dbms#dbms.image::ansible@kubernetes.cluster: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + k8s_host: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - get_input: gcp_project + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: + eval: .::dbms_name + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port interfaces: Standard: operations: @@ -6016,73 +13758,128 @@ node_types: primary: Ansible operation_host: ORCHESTRATOR environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file inputs: playbook: q: - - name: enable service - google.cloud.gcp_serviceusage_service: - name: '{{ SELF.gcp_service }}' - project: '{{ SELF.gcp_project }}' - delete: exit 0 - gcp.memorystore~gcp.service::terraform: - derived_from: gcp.memorystore + - name: create deployment + kubernetes.core.k8s: + wait: true + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.dbms_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.dbms_name }}' + template: + metadata: + labels: + app: '{{ SELF.dbms_name }}' + spec: + containers: + - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + name: '{{ SELF.dbms_name }}' + env: + - name: MYSQL_ROOT_PASSWORD + value: '{{ SELF.dbms_password }}' + ports: + - containerPort: 3306 + name: mysql + - name: create service + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.dbms_name }}' + namespace: default + spec: + ports: + - name: mysql + port: 3306 + targetPort: 3306 + selector: + app: '{{ SELF.dbms_name }}' + type: ClusterIP + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file + inputs: + playbook: + q: + - name: delete service + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: Service + name: '{{ SELF.dbms_name }}' + namespace: default + - name: delete deployment + kubernetes.core.k8s: + state: absent + api_version: apps/v1 + kind: Deployment + name: '{{ SELF.dbms_name }}' + namespace: default + mysql.dbms~mysql.dbms#dbms.image::kubernetes@kubernetes.cluster: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + k8s_host: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - get_input: gcp_project - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform - delete: - implementation: - primary: Terraform - defaults: - inputs: - main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - required_version: '>= 0.14.0' - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - resource: - google_project_service: - cloud_sql_admin: - - disable_on_destroy: false - project: '{{ SELF.gcp_project }}' - service: '{{ SELF.gcp_service }}' - docker.engine~docker.engine::ansible@local.machine: - derived_from: docker.engine - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file attributes: application_address: type: string - default: 127.0.0.1 + default: + eval: .::dbms_name + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port interfaces: Standard: operations: @@ -6093,53 +13890,66 @@ node_types: inputs: playbook: q: - - name: install docker - ansible.builtin.shell: curl -sSL https://get.docker.com | sh + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.dbms.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} + vars: + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.dbms_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.dbms_name }}' + template: + metadata: + labels: + app: '{{ SELF.dbms_name }}' + spec: + containers: + - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + name: '{{ SELF.dbms_name }}' + env: + - name: MYSQL_ROOT_PASSWORD + value: '{{ SELF.dbms_password }}' + ports: + - containerPort: 3306 + name: mysql + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.dbms_name }}' + spec: + ports: + - name: mysql + port: 3306 + targetPort: 3306 + selector: + app: '{{ SELF.dbms_name }}' + type: ClusterIP + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} rollout status deployment/{{ SELF.dbms_name }} --timeout 60s args: executable: /usr/bin/bash - - name: update service - ansible.builtin.copy: - dest: /lib/systemd/system/docker.service - content: | - [Unit] - Description=Docker Application Container Engine - Documentation=https://docs.docker.com - After=network-online.target docker.socket firewalld.service containerd.service time-set.target - Wants=network-online.target containerd.service - Requires=docker.socket - - [Service] - Type=notify - ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock - ExecReload=/bin/kill -s HUP $MAINPID - TimeoutStartSec=0 - RestartSec=2 - Restart=always - StartLimitBurst=3 - StartLimitInterval=60s - LimitNPROC=infinity - LimitCORE=infinity - TasksMax=infinity - Delegate=yes - KillMode=process - OOMScoreAdjust=-500 - - [Install] - WantedBy=multi-user.target - - name: restart service - ansible.builtin.systemd: - name: docker.service - state: restarted - enabled: 'yes' - daemon_reload: 'yes' - - name: add docker group - ansible.builtin.group: - name: docker - - name: add user to docker group - ansible.builtin.user: - name: '{{ SELF.os_ssh_user }}' - groups: docker - append: 'yes' + - name: let it cook + ansible.builtin.pause: + seconds: 10 delete: implementation: primary: Ansible @@ -6147,34 +13957,97 @@ node_types: inputs: playbook: q: - - name: delete docker packages - ansible.builtin.apt: - name: - - docker-ce - - docker-ce-cli - - containerd.io - - docker-buildx-plugin - - docker-compose-plugin - - docker-ce-rootless-extras - state: absent - purge: 'true' - autoremove: 'true' - - name: delete docker directories - ansible.builtin.file: - name: '{{ item }}' - state: absent - loop: - - /var/lib/docker - - /var/lib/containerd - docker.engine~docker.engine::terraform@local.machine: - derived_from: docker.engine + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.dbms_name }}.dbms.manifest.yaml' + - name: create manifest + ansible.builtin.copy: + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} + vars: + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.dbms_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.dbms_name }}' + template: + metadata: + labels: + app: '{{ SELF.dbms_name }}' + spec: + containers: + - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + name: '{{ SELF.dbms_name }}' + env: + - name: MYSQL_ROOT_PASSWORD + value: '{{ SELF.dbms_password }}' + ports: + - containerPort: 3306 + name: mysql + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.dbms_name }}' + spec: + ports: + - name: mysql + port: 3306 + targetPort: 3306 + selector: + app: '{{ SELF.dbms_name }}' + type: ClusterIP + - name: unapply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + mysql.dbms~mysql.dbms#dbms.image::terraform@kubernetes.cluster: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file attributes: application_address: type: string - default: 127.0.0.1 + default: + eval: .::dbms_name + application_port: + type: integer + default: 3306 + management_address: + type: string + default: + eval: .::application_address + management_port: + type: integer + default: + eval: .::application_port interfaces: Standard: operations: @@ -6189,198 +14062,199 @@ node_types: main: terraform: - required_providers: - - mysql: - source: hashicorp/local - version: 2.5.1 + - kubernetes: + source: hashicorp/kubernetes + version: 2.31.0 required_version: '>= 0.14.0' provider: - local: - - endpoint: 127.0.0.1:{{ HOST.management_port }} - password: '{{ HOST.dbms_password }}' - username: root + kubernetes: + - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} + client_key: ${file("{{ SELF.k8s_client_key_file }}")} + cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} + host: '{{ SELF.k8s_host }}' resource: - local_file: - tmp_service: - content: | - [Unit] - Description=Docker Application Container Engine - Documentation=https://docs.docker.com - After=network-online.target docker.socket firewalld.service containerd.service time-set.target - Wants=network-online.target containerd.service - Requires=docker.socket - - [Service] - Type=notify - ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock - ExecReload=/bin/kill -s HUP $MAINPID - TimeoutStartSec=0 - RestartSec=2 - Restart=always - StartLimitBurst=3 - StartLimitInterval=60s - LimitNPROC=infinity - LimitCORE=infinity - TasksMax=infinity - Delegate=yes - KillMode=process - OOMScoreAdjust=-500 - - [Install] - WantedBy=multi-user.target - filename: /tmp/docker.service - terraform_data: - docker: - - depends_on: local_file.tmp_service - provisioner: - local-exec: - - inline: - - curl -sSL https://get.docker.com | sudo sh - - sudo groupadd -f docker - - sudo usermod -aG docker {{ SELF.os_ssh_user }} - - sleep 10s - - cat /tmp/docker.service | sudo tee /lib/systemd/system/docker.service - - sudo systemctl daemon-reload - - sudo systemctl restart docker.service - - inline: - - sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras -y - - sudo rm -rf /var/lib/docker - - sudo rm -rf /var/lib/containerd - when: destroy - docker.engine~docker.engine::ansible@remote.machine: - derived_from: docker.engine + kubernetes_deployment_v1: + application: + - metadata: + - name: '{{ SELF.dbms_name }}' + spec: + - selector: + - match_labels: + app: '{{ SELF.dbms_name }}' + template: + - metadata: + - labels: + app: '{{ SELF.dbms_name }}' + spec: + - container: + - name: '{{ SELF.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + env: + - name: MYSQL_ROOT_PASSWORD + value: '{{ SELF.dbms_password }}' + port: + - container_port: 3306 + name: mysql + kubernetes_service_v1: + application: + - metadata: + - name: '{{ SELF.dbms_name }}' + spec: + - port: + - name: mysql + port: 3306 + target_port: 3306 + selector: + app: '{{ SELF.dbms_name }}' + type: ClusterIP + mysql.dbms~mysql.dbms#dbms.image::ansible@local.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + application_port: + type: string + default: 3001 + application_address: type: string - default: - get_input: os_ssh_user - os_ssh_key_file: + default: 127.0.0.1 + attributes: + management_address: type: string default: - get_input: os_ssh_key_file + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: + eval: .::application_port + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: install docker - ansible.builtin.shell: curl -sSL https://get.docker.com | sh - args: - executable: /usr/bin/bash - - name: update service + - name: installing mysql + ansible.builtin.apt: + name: + - mysql-server + - mysql-client + - python3-mysqldb + - libmysqlclient-dev + state: present + update_cache: 'yes' + - name: start and enable mysql service + ansible.builtin.systemd: + name: mysql + state: started + enabled: 'yes' + - name: enable passwordless login ansible.builtin.copy: - dest: /lib/systemd/system/docker.service + dest: '{{ item }}' content: | - [Unit] - Description=Docker Application Container Engine - Documentation=https://docs.docker.com - After=network-online.target docker.socket firewalld.service containerd.service time-set.target - Wants=network-online.target containerd.service - Requires=docker.socket - - [Service] - Type=notify - ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock - ExecReload=/bin/kill -s HUP $MAINPID - TimeoutStartSec=0 - RestartSec=2 - Restart=always - StartLimitBurst=3 - StartLimitInterval=60s - LimitNPROC=infinity - LimitCORE=infinity - TasksMax=infinity - Delegate=yes - KillMode=process - OOMScoreAdjust=-500 - - [Install] - WantedBy=multi-user.target - - name: restart service + [client] + user=root + password={{ SELF.dbms_password }} + loop: + - /root/.my.cnf + - /home/{{ SELF.os_ssh_user }}/.my.cnf + - name: configure port (e.g., since 3306 is blocked by the provider) + ansible.builtin.lineinfile: + path: /etc/mysql/mysql.conf.d/mysqld.cnf + regexp: ^# port + line: port = {{ SELF.application_port }} + backup: 'yes' + - name: enable remote login + ansible.builtin.lineinfile: + path: /etc/mysql/mysql.conf.d/mysqld.cnf + regexp: ^bind-address + line: bind-address = 0.0.0.0 + backup: 'yes' + - name: restart mysql ansible.builtin.systemd: - name: docker.service + name: mysql state: restarted - enabled: 'yes' - daemon_reload: 'yes' - - name: add docker group - ansible.builtin.group: - name: docker - - name: add user to docker group - ansible.builtin.user: - name: '{{ SELF.os_ssh_user }}' - groups: docker - append: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' + - name: create all root + community.mysql.mysql_user: + name: root + password: '{{ SELF.dbms_password }}' + priv: '*.*:ALL' + host: '%' + state: present + login_host: localhost + login_password: '{{ SELF.dbms_password }}' + login_port: '{{ SELF.application_port }}' + login_user: root + - name: delete localhost root + community.mysql.mysql_user: + name: root + host: localhost + state: absent + login_host: localhost + login_password: '{{ SELF.dbms_password }}' + login_port: '{{ SELF.application_port }}' + login_user: root delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: delete docker packages + - name: uninstalling mysql ansible.builtin.apt: name: - - docker-ce - - docker-ce-cli - - containerd.io - - docker-buildx-plugin - - docker-compose-plugin - - docker-ce-rootless-extras + - mysql-server + - mysql-client + - python3-mysqldb + - libmysqlclient-dev state: absent - purge: 'true' - autoremove: 'true' - - name: delete docker directories + - name: remove passwordless login ansible.builtin.file: name: '{{ item }}' state: absent loop: - - /var/lib/docker - - /var/lib/containerd - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - docker.engine~docker.engine::terraform@remote.machine: - derived_from: docker.engine + - /root/.my.cnf + - /home/{{ SELF.os_ssh_user }}/.my.cnf + mysql.dbms~mysql.dbms#dbms.image::terraform@local.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + application_port: type: string - default: - get_input: os_ssh_user - os_ssh_key_file: + default: 3001 + application_address: type: string - default: - get_input: os_ssh_key_file - os_ssh_host: + default: 127.0.0.1 + attributes: + management_address: type: string default: eval: .::.requirements::[.name=host]::.target::management_address - attributes: - application_address: - type: string - default: 127.0.0.1 + management_port: + type: integer + default: + eval: .::application_port + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address interfaces: Standard: operations: @@ -6393,61 +14267,58 @@ node_types: defaults: inputs: main: - terraform: - - required_version: '>= 0.14.0' resource: - terraform_data: - docker: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - content: | - [Unit] - Description=Docker Application Container Engine - Documentation=https://docs.docker.com - After=network-online.target docker.socket firewalld.service containerd.service time-set.target - Wants=network-online.target containerd.service - Requires=docker.socket + local_file: + tmp_script: + content: | - [Service] - Type=notify - ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock - ExecReload=/bin/kill -s HUP $MAINPID - TimeoutStartSec=0 - RestartSec=2 - Restart=always - StartLimitBurst=3 - StartLimitInterval=60s - LimitNPROC=infinity - LimitCORE=infinity - TasksMax=infinity - Delegate=yes - KillMode=process - OOMScoreAdjust=-500 + #!/usr/bin/bash + set -e + export DEBIAN_FRONTEND="noninteractive" - [Install] - WantedBy=multi-user.target - destination: /tmp/docker.service - remote-exec: - - inline: - - curl -sSL https://get.docker.com | sudo sh - - sudo groupadd -f docker - - sudo usermod -aG docker {{ SELF.os_ssh_user }} - - sleep 10s - - cat /tmp/docker.service | sudo tee /lib/systemd/system/docker.service - - sudo systemctl daemon-reload - - sudo systemctl restart docker.service + DBMS_PASSWORD=$1 + DBMS_PORT=$2 + + # Set password + debconf-set-selections <<< "mysql-server mysql-server/root_password password ${DBMS_PASSWORD}" + debconf-set-selections <<< "mysql-server mysql-server/root_password_again password ${DBMS_PASSWORD}" + + # Install mysql + apt-get update -y + apt-get -y install mysql-server + + # Passwordless auth + cat < /root/.my.cnf + [client] + user=root + password=${DBMS_PASSWORD} + EOF + + # Listen on all interfaces + sed -i "s/127\.0\.0\.1/0\.0\.0\.0/g" /etc/mysql/mysql.conf.d/mysqld.cnf + + # Listen on custom port + sed -i "s/# port.*/port = ${DBMS_PORT}/g" /etc/mysql/mysql.conf.d/mysqld.cnf + + # Configure any host for root + mysql -u root -e 'USE mysql; UPDATE user SET host = "%" WHERE user = "root"; FLUSH PRIVILEGES;' + mysql -u root -e 'USE mysql; DELETE FROM user WHERE user = "root" and host = "localhost"; FLUSH PRIVILEGES;' + + # Enable service + systemctl enable mysql + + # Restart service + systemctl restart mysql + filename: /tmp/install-mysql-dbms.sh + terraform_data: + local: + - depends_on: local_file.tmp_script + provisioner: + local-exec: - inline: - - sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras -y - - sudo rm -rf /var/lib/docker - - sudo rm -rf /var/lib/containerd - when: destroy - docker.engine~software.application#apt.package::ansible@*->remote.machine: - derived_from: docker.engine + - sudo bash /tmp/install-mysql-dbms.sh {{ SELF.dbms_password }} {{ SELF.application_port }} + mysql.dbms~mysql.dbms#dbms.image::ansible@remote.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -6460,14 +14331,28 @@ node_types: type: string default: get_input: os_ssh_key_file - application_directory: + application_port: + type: string + default: 3001 + application_address: + type: string + default: 127.0.0.1 + attributes: + management_address: type: string default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: + eval: .::application_port + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address interfaces: Standard: operations: @@ -6482,196 +14367,105 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: run setup script - ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - args: - executable: /bin/bash - when: '".artifacts::apt_package::script" | eval != ""' - - name: add apt key - ansible.builtin.apt_key: - url: '{{ ".artifacts::apt_package::key" | eval }}' - keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - state: present - when: '".artifacts::apt_package::key" | eval != ""' - - name: add apt repository - ansible.builtin.apt_repository: - repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} - filename: '{{ ".artifacts::apt_package::repository" | eval }}' - state: present - when: '".artifacts::apt_package::source" | eval != ""' - - name: update apt cache - ansible.builtin.apt: - update_cache: 'yes' - - name: install dependencies - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' - state: present - when: '".artifacts::apt_package::dependencies" | eval != ""' - - name: install package + - name: installing mysql ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' + name: + - mysql-server + - mysql-client + - python3-mysqldb + - libmysqlclient-dev state: present - environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/create.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - mode: '0755' - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/create.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - configure: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/configure.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - mode: '0755' - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/configure.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - start: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/start.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - mode: '0755' - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/start.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - stop: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation + update_cache: 'yes' + - name: start and enable mysql service + ansible.builtin.systemd: + name: mysql + state: started + enabled: 'yes' + - name: enable passwordless login ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/stop.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - mode: '0755' - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/stop.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + dest: '{{ item }}' + content: | + [client] + user=root + password={{ SELF.dbms_password }} + loop: + - /root/.my.cnf + - /home/{{ SELF.os_ssh_user }}/.my.cnf + - name: configure port (e.g., since 3306 is blocked by the provider) + ansible.builtin.lineinfile: + path: /etc/mysql/mysql.conf.d/mysqld.cnf + regexp: ^# port + line: port = {{ SELF.application_port }} + backup: 'yes' + - name: enable remote login + ansible.builtin.lineinfile: + path: /etc/mysql/mysql.conf.d/mysqld.cnf + regexp: ^bind-address + line: bind-address = 0.0.0.0 + backup: 'yes' + - name: restart mysql + ansible.builtin.systemd: + name: mysql + state: restarted + - name: create all root + community.mysql.mysql_user: + name: root + password: '{{ SELF.dbms_password }}' + priv: '*.*:ALL' + host: '%' + state: present + login_host: localhost + login_password: '{{ SELF.dbms_password }}' + login_port: '{{ SELF.application_port }}' + login_user: root + - name: delete localhost root + community.mysql.mysql_user: + name: root + host: localhost + state: absent + login_host: localhost + login_password: '{{ SELF.dbms_password }}' + login_port: '{{ SELF.application_port }}' + login_user: root playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - delete: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/delete.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - mode: '0755' - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/delete.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - - name: uninstall package + - '--user={{ SELF.os_ssh_user }}' + delete: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: uninstalling mysql ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' + name: + - mysql-server + - mysql-client + - python3-mysqldb + - libmysqlclient-dev + state: absent + - name: remove passwordless login + ansible.builtin.file: + name: '{{ item }}' state: absent + loop: + - /root/.my.cnf + - /home/{{ SELF.os_ssh_user }}/.my.cnf playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - docker.engine~software.application#apt.archive::terraform@*->remote.machine: - derived_from: docker.engine + mysql.dbms~mysql.dbms#dbms.image::terraform@remote.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' + vintner_orchestrator: unfurl properties: os_ssh_user: type: string @@ -6685,14 +14479,28 @@ node_types: type: string default: eval: .::.requirements::[.name=host]::.target::management_address - application_directory: + application_port: + type: string + default: 3001 + application_address: + type: string + default: 127.0.0.1 + attributes: + management_address: type: string default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name + eval: .::.requirements::[.name=host]::.target::management_address + management_port: + type: integer + default: + eval: .::application_port + capabilities: + endpoint: + type: unfurl.capabilities.Endpoint.Ansible + properties: + connection: ssh + host: + eval: .parent::management_address interfaces: Standard: operations: @@ -6716,170 +14524,54 @@ node_types: provisioner: file: - content: | - #!/usr/bin/bash - set -e - - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi - - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi - - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then - echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} - fi - - # Update apt cache - apt-get update -y - - # Install dependencies - if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then - apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y - fi - - # Install package - {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-docker.engine {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh #!/usr/bin/bash set -e + export DEBIAN_FRONTEND="noninteractive" - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e + DBMS_PASSWORD=$1 + DBMS_PORT=$2 - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e + # Set password + debconf-set-selections <<< "mysql-server mysql-server/root_password password ${DBMS_PASSWORD}" + debconf-set-selections <<< "mysql-server mysql-server/root_password_again password ${DBMS_PASSWORD}" - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + # Install mysql + apt-get update -y + apt-get -y install mysql-server - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e + # Passwordless auth + cat < /root/.my.cnf + [client] + user=root + password=${DBMS_PASSWORD} + EOF - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e + # Listen on all interfaces + sed -i "s/127\.0\.0\.1/0\.0\.0\.0/g" /etc/mysql/mysql.conf.d/mysqld.cnf - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + # Listen on custom port + sed -i "s/# port.*/port = ${DBMS_PORT}/g" /etc/mysql/mysql.conf.d/mysqld.cnf - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh + # Configure any host for root + mysql -u root -e 'USE mysql; UPDATE user SET host = "%" WHERE user = "root"; FLUSH PRIVILEGES;' + mysql -u root -e 'USE mysql; DELETE FROM user WHERE user = "root" and host = "localhost"; FLUSH PRIVILEGES;' - # Delete application directory - rm -rf "{{ SELF.application_directory }}" + # Enable service + systemctl enable mysql - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-docker.engine.sh + # Restart service + systemctl restart mysql + destination: /tmp/install-mysql-dbms.sh remote-exec: - inline: - - sudo bash /tmp/create-docker.engine.sh - - sudo bash /tmp/configure-docker.engine.sh - - sudo bash /tmp/start-docker.engine.sh - - inline: - - sudo bash /tmp/stop-docker.engine.sh - - sudo bash /tmp/delete-docker.engine.sh - when: destroy - docker.engine~software.application#tar.archive::ansible@*->remote.machine: - derived_from: docker.engine + - sudo bash /tmp/install-mysql-dbms.sh {{ SELF.dbms_password }} {{ SELF.application_port }} + mysql.dbms~software.application#apt.package::ansible@*->local.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -6894,41 +14586,44 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") - - name: extract deployment artifact from URL in application directory - ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: |- - APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -6945,21 +14640,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -6976,21 +14663,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -7011,21 +14690,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "stop" missing @@ -7046,21 +14717,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -7081,27 +14744,15 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - docker.engine~software.application#tar.archive::terraform@*->remote.machine: - derived_from: docker.engine + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + mysql.dbms~software.application#apt.package::terraform@*->local.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -7123,154 +14774,169 @@ node_types: inputs: main: resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-docker.engine - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-docker.engine {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-docker.engine -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-mysql.dbms.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-mysql.dbms.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-mysql.dbms.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-mysql.dbms.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-docker.engine.sh - - content: | - #!/usr/bin/bash - set -e + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh + # Delete application directory + rm -rf "{{ SELF.application_directory }}" - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-docker.engine.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-mysql.dbms.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: - inline: - - sudo bash /tmp/create-docker.engine.sh - - sudo bash /tmp/configure-docker.engine.sh - - sudo bash /tmp/start-docker.engine.sh + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh - inline: - - sudo bash /tmp/stop-docker.engine.sh - - sudo bash /tmp/delete-docker.engine.sh + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh when: destroy - docker.engine~software.application#zip.archive::ansible@*->remote.machine: - derived_from: docker.engine + mysql.dbms~software.application#apt.package::ansible@*->remote.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -7305,36 +14971,40 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache ansible.builtin.apt: - name: unzip update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: |- - APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -7487,12 +15157,16 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - docker.engine~software.application#zip.archive::terraform@*->remote.machine: - derived_from: docker.engine + mysql.dbms~software.application#apt.package::terraform@*->remote.machine: + derived_from: mysql.dbms metadata: vintner_generated: 'true' properties: @@ -7538,30 +15212,47 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-docker.engine - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + # Create application directory mkdir -p {{ SELF.application_directory }} # Create application environment cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" APPLICATION_NAME="{{ SELF.application_name }}" - _HOSTING="{{ SELF._hosting }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-docker.engine {{ ".artifacts::zip_archive::file" | eval }} - fi - - # Extract deployment artifact - unzip /tmp/artifact-docker.engine -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -7578,7 +15269,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/create.sh - destination: /tmp/create-docker.engine.sh + destination: /tmp/create-mysql.dbms.sh - content: | #!/usr/bin/bash set -e @@ -7596,17 +15287,11 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/configure.sh - destination: /tmp/configure-docker.engine.sh + destination: /tmp/configure-mysql.dbms.sh - content: | #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - # Copy operation cat < {{ SELF.application_directory }}/.vintner/start.sh #!/usr/bin/bash @@ -7620,17 +15305,11 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/start.sh - destination: /tmp/start-docker.engine.sh + destination: /tmp/start-mysql.dbms.sh - content: | #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - # Copy operation cat < {{ SELF.application_directory }}/.vintner/stop.sh #!/usr/bin/bash @@ -7644,7 +15323,7 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - destination: /tmp/stop-docker.engine.sh + destination: /tmp/stop-mysql.dbms.sh - content: | #!/usr/bin/bash set -e @@ -7654,169 +15333,624 @@ node_types: #!/usr/bin/bash set -e - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + destination: /tmp/delete-mysql.dbms.sh + remote-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.dbms~software.application#tar.archive::ansible@*->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-docker.engine.sh - remote-exec: + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + mysql.dbms~software.application#tar.archive::terraform@*->local.machine: + derived_from: mysql.dbms + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-mysql.dbms + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-mysql.dbms -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-mysql.dbms.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-mysql.dbms.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-mysql.dbms.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-mysql.dbms.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-mysql.dbms.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: - inline: - - sudo bash /tmp/create-docker.engine.sh - - sudo bash /tmp/configure-docker.engine.sh - - sudo bash /tmp/start-docker.engine.sh + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh - inline: - - sudo bash /tmp/stop-docker.engine.sh - - sudo bash /tmp/delete-docker.engine.sh + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh when: destroy - mysql.dbms~mysql.dbms#dbms.image::ansible@docker.engine->local.machine: + mysql.dbms~software.application#tar.archive::ansible@*->remote.machine: derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - attributes: - application_address: + properties: + os_ssh_user: type: string - default: 127.0.0.1 - application_port: + default: + get_input: os_ssh_user + os_ssh_key_file: type: string - default: 3306 - management_address: + default: + get_input: os_ssh_key_file + application_directory: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: 3306 + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: start container - community.docker.docker_container: - name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - network_mode: host - env: - MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password | string }}' - delete: + - name: wait for ssh + wait_for_connection: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: delete container - community.docker.docker_container: - name: '{{ SELF.dbms_name }}' - state: absent - mysql.dbms~mysql.dbms#dbms.image::compose@docker.engine->local.machine: - derived_from: mysql.dbms - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - attributes: - application_address: - type: string - default: 127.0.0.1 - application_port: - type: integer - default: 3306 - management_address: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: 3306 - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address - interfaces: - Standard: - operations: - create: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.compose.yaml' - - name: create compose + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.dbms_name }}' - services: - application: - container_name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - network_mode: host - environment: - MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: - executable: /usr/bin/bash - - name: let it cook - ansible.builtin.pause: - seconds: 10 + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.compose.yaml' - - name: create compose + - name: wait for ssh + wait_for_connection: + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.dbms_name }}' - services: - application: - container_name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - network_mode: host - environment: - MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: - executable: /usr/bin/bash - mysql.dbms~mysql.dbms#dbms.image::terraform@docker.engine->local.machine: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.dbms~software.application#tar.archive::terraform@*->remote.machine: derived_from: mysql.dbms metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: os_ssh_user: type: string @@ -7830,27 +15964,14 @@ node_types: type: string default: eval: .::.requirements::[.name=host]::.target::management_address - attributes: - application_address: - type: string - default: 127.0.0.1 - application_port: - type: integer - default: 3306 - management_address: + application_directory: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: 3306 - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -7863,165 +15984,305 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - docker: - source: kreuzwerker/docker - version: 3.0.2 - provider: - docker: - - host: unix:///var/run/docker.sock resource: - docker_container: - application: - - name: '{{ SELF.dbms_name }}' - image: ${docker_image.image.image_id} - network_mode: host - env: - - MYSQL_ROOT_PASSWORD={{ SELF.dbms_password }} - docker_image: - image: - - name: mysql:{{ ".artifacts::dbms_image::file" | eval }} - mysql.dbms~mysql.dbms#dbms.image::ansible@docker.engine->remote.machine: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-mysql.dbms + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-mysql.dbms -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-mysql.dbms.sh + remote-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.dbms~software.application#zip.archive::ansible@*->local.machine: derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - attributes: - application_address: - type: string - default: 127.0.0.1 - application_port: - type: string - default: 3306 - management_address: + application_directory: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: 3306 + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: start container - community.docker.docker_container: - name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - network_mode: host - env: - MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password | string }}' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - delete: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: stop container - community.docker.docker_container: - name: '{{ SELF.application_name }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~mysql.dbms#dbms.image::compose@docker.engine->remote.machine: - derived_from: mysql.dbms - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - attributes: - application_address: - type: string - default: 127.0.0.1 - application_port: - type: integer - default: 3306 - management_address: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: 3306 - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address - interfaces: - Standard: - operations: - create: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.compose.yaml' - - name: create compose + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.dbms_name }}' - services: - application: - container_name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - network_mode: host - environment: - MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - - name: let it cook - ansible.builtin.pause: - seconds: 10 + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" delete: implementation: primary: Ansible @@ -8029,69 +16290,39 @@ node_types: inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.compose.yaml' - - name: create compose + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.dbms_name }}' - services: - application: - container_name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - network_mode: host - environment: - MYSQL_ROOT_PASSWORD: '{{ SELF.dbms_password }}' - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - mysql.dbms~mysql.dbms#dbms.image::terraform@docker.engine->remote.machine: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + mysql.dbms~software.application#zip.archive::terraform@*->local.machine: derived_from: mysql.dbms metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - attributes: - application_address: - type: string - default: 127.0.0.1 - application_port: - type: integer - default: 3306 - management_address: + application_directory: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: 3306 - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -8104,383 +16335,641 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - docker: - source: kreuzwerker/docker - version: 3.0.2 - required_version: '>= 0.14.0' - provider: - docker: - - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 - ssh_opts: - - '-i' - - '{{ SELF.os_ssh_key_file }}' - - '-o' - - IdentitiesOnly=yes - - '-o' - - BatchMode=yes - - '-o' - - UserKnownHostsFile=/dev/null - - '-o' - - StrictHostKeyChecking=no resource: - docker_container: - application: - - name: '{{ SELF.dbms_name }}' - image: ${docker_image.image.image_id} - network_mode: host - env: - - MYSQL_ROOT_PASSWORD={{ SELF.dbms_password }} - docker_image: - image: - - name: mysql:{{ ".artifacts::dbms_image::file" | eval }} - mysql.dbms~mysql.dbms#dbms.image::ansible@gcp.cloudsql: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-mysql.dbms + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-mysql.dbms -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-mysql.dbms.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-mysql.dbms.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-mysql.dbms.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-mysql.dbms.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-mysql.dbms.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.dbms~software.application#zip.archive::ansible@*->remote.machine: derived_from: mysql.dbms metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: + os_ssh_user: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_project - dbms_ssl_mode: - type: string - default: Preferred - attributes: - application_port: - type: string - default: 3306 - management_address: + get_input: os_ssh_key_file + application_directory: type: string default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: create a instance - register: instance_info - google.cloud.gcp_sql_instance: - name: '{{ SELF.dbms_name }}' - database_version: MYSQL_{{ ".artifacts::dbms_image::file" | eval | replace(".", "_") }} - settings: - tier: db-f1-micro - availability_type: REGIONAL - backup_configuration: - binary_log_enabled: true - enabled: true - ip_configuration: - authorized_networks: - - value: 0.0.0.0/0 - region: '{{ SELF.gcp_region }}' - project: '{{ SELF.gcp_project }}' - - name: set root password - google.cloud.gcp_sql_user: - name: root - host: '%' - password: '{{ SELF.dbms_password }}' - instance: '{{ instance_info }}' - project: '{{ SELF.gcp_project }}' - - name: aet attributes - set_fact: - application_address: '{{ instance_info.ipAddresses[0].ipAddress | trim }}' - resultTemplate: | - name: SELF - attributes: - application_address: '{{ outputs.application_address }}' - outputs: - application_address: - delete: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: Activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: Delete Instance - ansible.builtin.shell: gcloud sql instances delete {{ SELF.dbms_name }} --quiet + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - mysql.dbms~mysql.dbms#dbms.image::terraform@gcp.cloudsql: - derived_from: mysql.dbms - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: - type: string - default: - get_input: gcp_project - dbms_ssl_mode: - type: string - default: Preferred - attributes: - application_port: - type: string - default: 3306 - management_address: - type: string - default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' delete: implementation: - primary: Terraform - defaults: - outputs: - application_address: application_address - inputs: - main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 4.67.0 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: ${google_sql_database_instance.dbms.public_ip_address} - resource: - google_sql_database_instance: - dbms: - - database_version: MYSQL_{{ ".artifacts::dbms_image::file" | eval | replace(".", "_") }} - deletion_protection: false - name: '{{ SELF.dbms_name }}' - root_password: '{{ SELF.dbms_password }}' - settings: - - availability_type: REGIONAL - backup_configuration: - - binary_log_enabled: true - enabled: true - ip_configuration: - - authorized_networks: - - name: public - value: 0.0.0.0/0 - ipv4_enabled: true - tier: db-f1-micro - google_sql_user: - user: - - host: '%' - instance: ${google_sql_database_instance.dbms.name} - name: root - password: ${google_sql_database_instance.dbms.root_password} - mysql.dbms~mysql.dbms#dbms.image::ansible@kubernetes.cluster: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + mysql.dbms~software.application#zip.archive::terraform@*->remote.machine: derived_from: mysql.dbms metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: + os_ssh_user: type: string default: - get_input: k8s_client_cert_file - k8s_client_key_file: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: k8s_client_key_file - attributes: - application_address: + get_input: os_ssh_key_file + os_ssh_host: type: string default: - eval: .::dbms_name - application_port: - type: integer - default: 3306 - management_address: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: type: string default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: - create: + configure: implementation: - primary: Ansible - operation_host: ORCHESTRATOR - environment: - K8S_AUTH_HOST: - eval: .::k8s_host - K8S_AUTH_SSL_CA_CERT: - eval: .::k8s_ca_cert_file - K8S_AUTH_CERT_FILE: - eval: .::k8s_client_cert_file - K8S_AUTH_KEY_FILE: - eval: .::k8s_client_key_file - inputs: - playbook: - q: - - name: create deployment - kubernetes.core.k8s: - wait: true - definition: - apiVersion: apps/v1 - kind: Deployment - metadata: - name: '{{ SELF.dbms_name }}' - namespace: default - spec: - selector: - matchLabels: - app: '{{ SELF.dbms_name }}' - template: - metadata: - labels: - app: '{{ SELF.dbms_name }}' - spec: - containers: - - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - name: '{{ SELF.dbms_name }}' - env: - - name: MYSQL_ROOT_PASSWORD - value: '{{ SELF.dbms_password }}' - ports: - - containerPort: 3306 - name: mysql - - name: create service - kubernetes.core.k8s: - definition: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.dbms_name }}' - namespace: default - spec: - ports: - - name: mysql - port: 3306 - targetPort: 3306 - selector: - app: '{{ SELF.dbms_name }}' - type: ClusterIP + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-mysql.dbms + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + DBMS_NAME="{{ SELF.dbms_name }}" + APPLICATION_NAME="{{ SELF.application_name }}" + DBMS_PASSWORD="{{ SELF.dbms_password }}" + DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-mysql.dbms -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + destination: /tmp/create-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + destination: /tmp/start-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + destination: /tmp/stop-mysql.dbms.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + destination: /tmp/delete-mysql.dbms.sh + remote-exec: + - inline: + - sudo bash /tmp/create-mysql.dbms.sh + - sudo bash /tmp/configure-mysql.dbms.sh + - sudo bash /tmp/start-mysql.dbms.sh + - inline: + - sudo bash /tmp/stop-mysql.dbms.sh + - sudo bash /tmp/delete-mysql.dbms.sh + when: destroy + mysql.database~mysql.database::ansible@mysql.dbms->docker.engine->local.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: get dbms container info + community.docker.docker_container_info: + name: '{{ HOST.dbms_name }}' + register: dbms_container_info + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root delete: implementation: primary: Ansible operation_host: ORCHESTRATOR - environment: - K8S_AUTH_HOST: - eval: .::k8s_host - K8S_AUTH_SSL_CA_CERT: - eval: .::k8s_ca_cert_file - K8S_AUTH_CERT_FILE: - eval: .::k8s_client_cert_file - K8S_AUTH_KEY_FILE: - eval: .::k8s_client_key_file inputs: playbook: q: - - name: delete service - kubernetes.core.k8s: + - name: delete user (with privileges) + community.mysql.mysql_user: state: absent - api_version: v1 - kind: Service - name: '{{ SELF.dbms_name }}' - namespace: default - - name: delete deployment - kubernetes.core.k8s: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: delete database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' state: absent - api_version: apps/v1 - kind: Deployment - name: '{{ SELF.dbms_name }}' - namespace: default - mysql.dbms~mysql.dbms#dbms.image::kubernetes@kubernetes.cluster: - derived_from: mysql.dbms + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + mysql.database~mysql.database::compose@mysql.dbms->docker.engine->local.machine: + derived_from: mysql.database metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: - type: string - default: - get_input: k8s_client_key_file - attributes: - application_address: - type: string - default: - eval: .::dbms_name - application_port: - type: integer - default: 3306 - management_address: - type: string - default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port interfaces: Standard: operations: @@ -8491,164 +16980,88 @@ node_types: inputs: playbook: q: - - name: touch manifest - register: manifest + - name: touch compose + register: compose ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.dbms.manifest.yaml' - - name: create manifest + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + - name: create compose ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: | - {{ deployment | to_yaml }} - --- - {{ service | to_yaml }} + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' vars: - deployment: - apiVersion: apps/v1 - kind: Deployment - metadata: - name: '{{ SELF.dbms_name }}' - namespace: default - spec: - selector: - matchLabels: - app: '{{ SELF.dbms_name }}' - template: - metadata: - labels: - app: '{{ SELF.dbms_name }}' - spec: - containers: - - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - name: '{{ SELF.dbms_name }}' - env: - - name: MYSQL_ROOT_PASSWORD - value: '{{ SELF.dbms_password }}' - ports: - - containerPort: 3306 - name: mysql - service: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.dbms_name }}' - spec: - ports: - - name: mysql - port: 3306 - targetPort: 3306 - selector: - app: '{{ SELF.dbms_name }}' - type: ClusterIP - - name: apply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} - args: - executable: /usr/bin/bash - - name: wait for deployment - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} rollout status deployment/{{ SELF.dbms_name }} --timeout 60s + manifest: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + services: + job: + container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d args: executable: /usr/bin/bash - name: let it cook ansible.builtin.pause: seconds: 10 - delete: - implementation: - primary: Ansible - operation_host: ORCHESTRATOR - inputs: - playbook: - q: - - name: touch manifest - register: manifest - ansible.builtin.tempfile: - suffix: '{{ SELF.dbms_name }}.dbms.manifest.yaml' - - name: create manifest - ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: | - {{ deployment | to_yaml }} - --- - {{ service | to_yaml }} - vars: - deployment: - apiVersion: apps/v1 - kind: Deployment - metadata: - name: '{{ SELF.dbms_name }}' - namespace: default - spec: - selector: - matchLabels: - app: '{{ SELF.dbms_name }}' - template: - metadata: - labels: - app: '{{ SELF.dbms_name }}' - spec: - containers: - - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - name: '{{ SELF.dbms_name }}' - env: - - name: MYSQL_ROOT_PASSWORD - value: '{{ SELF.dbms_password }}' - ports: - - containerPort: 3306 - name: mysql - service: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.dbms_name }}' - spec: - ports: - - name: mysql - port: 3306 - targetPort: 3306 - selector: - app: '{{ SELF.dbms_name }}' - type: ClusterIP - - name: unapply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash - mysql.dbms~mysql.dbms#dbms.image::terraform@kubernetes.cluster: - derived_from: mysql.dbms + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + services: + job: + container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + mysql.database~mysql.database::terraform@mysql.dbms->docker.engine->local.machine: + derived_from: mysql.database metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: - type: string - default: - get_input: k8s_client_key_file - attributes: - application_address: - type: string - default: - eval: .::dbms_name - application_port: - type: integer - default: 3306 - management_address: - type: string - default: - eval: .::application_address - management_port: - type: integer - default: - eval: .::application_port interfaces: Standard: operations: @@ -8663,53 +17076,33 @@ node_types: main: terraform: - required_providers: - - kubernetes: - source: hashicorp/kubernetes - version: 2.31.0 - required_version: '>= 0.14.0' + - mysql: + source: petoju/mysql + version: 3.0.48 provider: - kubernetes: - - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} - client_key: ${file("{{ SELF.k8s_client_key_file }}")} - cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} - host: '{{ SELF.k8s_host }}' + mysql: + - endpoint: 127.0.0.1:{{ HOST.management_port }} + password: '{{ HOST.dbms_password }}' + username: root resource: - kubernetes_deployment_v1: - application: - - metadata: - - name: '{{ SELF.dbms_name }}' - spec: - - selector: - - match_labels: - app: '{{ SELF.dbms_name }}' - template: - - metadata: - - labels: - app: '{{ SELF.dbms_name }}' - spec: - - container: - - name: '{{ SELF.dbms_name }}' - image: mysql:{{ ".artifacts::dbms_image::file" | eval }} - env: - - name: MYSQL_ROOT_PASSWORD - value: '{{ SELF.dbms_password }}' - port: - - container_port: 3306 - name: mysql - kubernetes_service_v1: - application: - - metadata: - - name: '{{ SELF.dbms_name }}' - spec: - - port: - - name: mysql - port: 3306 - target_port: 3306 - selector: - app: '{{ SELF.dbms_name }}' - type: ClusterIP - mysql.dbms~mysql.dbms#dbms.image::ansible@remote.machine: - derived_from: mysql.dbms + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + mysql.database~mysql.database::ansible@mysql.dbms->docker.engine->remote.machine: + derived_from: mysql.database metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -8722,28 +17115,6 @@ node_types: type: string default: get_input: os_ssh_key_file - application_port: - type: string - default: 3001 - application_address: - type: string - default: 127.0.0.1 - attributes: - management_address: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: - eval: .::application_port - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address interfaces: Standard: operations: @@ -8758,66 +17129,60 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: installing mysql + - name: install pip ansible.builtin.apt: - name: - - mysql-server - - mysql-client - - python3-mysqldb - - libmysqlclient-dev + name: python3-pip state: present - update_cache: 'yes' - - name: start and enable mysql service - ansible.builtin.systemd: - name: mysql - state: started - enabled: 'yes' - - name: enable passwordless login - ansible.builtin.copy: - dest: '{{ item }}' - content: | - [client] - user=root - password={{ SELF.dbms_password }} - loop: - - /root/.my.cnf - - /home/{{ SELF.os_ssh_user }}/.my.cnf - - name: configure port (e.g., since 3306 is blocked by the provider) - ansible.builtin.lineinfile: - path: /etc/mysql/mysql.conf.d/mysqld.cnf - regexp: ^# port - line: port = {{ SELF.application_port }} - backup: 'yes' - - name: enable remote login - ansible.builtin.lineinfile: - path: /etc/mysql/mysql.conf.d/mysqld.cnf - regexp: ^bind-address - line: bind-address = 0.0.0.0 - backup: 'yes' - - name: restart mysql - ansible.builtin.systemd: - name: mysql - state: restarted - - name: create all root + - name: install pymysql + ansible.builtin.pip: + name: pymysql + state: present + - name: get dbms container info + community.docker.docker_container_info: + name: '{{ HOST.dbms_name }}' + register: dbms_container_info + - name: forward port + when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" + community.docker.docker_container: + name: '{{ HOST.dbms_name }}-port-forward' + image: nicolaka/netshoot:v0.13 + command: socat TCP6-LISTEN:3306,fork TCP:{{ HOST.dbms_name }}:3306 + ports: + - '{{ HOST.application_port }}:3306' + - name: create forwarding network + community.docker.docker_network: + name: '{{ HOST.dbms_name }}-port-forward' + connected: + - '{{ HOST.dbms_name }}-port-forward' + - '{{ HOST.dbms_name }}' + when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: create user (with privileges) community.mysql.mysql_user: - name: root - password: '{{ SELF.dbms_password }}' - priv: '*.*:ALL' + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' host: '%' - state: present - login_host: localhost - login_password: '{{ SELF.dbms_password }}' - login_port: '{{ SELF.application_port }}' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' login_user: root - - name: delete localhost root - community.mysql.mysql_user: - name: root - host: localhost + - name: unforward port + when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" + community.docker.docker_container: + name: '{{ HOST.dbms_name }}-port-forward' state: absent - login_host: localhost - login_password: '{{ SELF.dbms_password }}' - login_port: '{{ SELF.application_port }}' - login_user: root + - name: remove forwarding network + community.docker.docker_network: + name: '{{ HOST.dbms_name }}-port-forward' + state: absent + when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' @@ -8833,27 +17198,136 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: uninstalling mysql - ansible.builtin.apt: - name: - - mysql-server - - mysql-client - - python3-mysqldb - - libmysqlclient-dev + - name: delete user (with privileges) + community.mysql.mysql_user: state: absent - - name: remove passwordless login - ansible.builtin.file: - name: '{{ item }}' + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: delete database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' state: absent - loop: - - /root/.my.cnf - - /home/{{ SELF.os_ssh_user }}/.my.cnf + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~mysql.dbms#dbms.image::terraform@remote.machine: - derived_from: mysql.dbms + mysql.database~mysql.database::compose@mysql.dbms->docker.engine->remote.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + services: + job: + container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + services: + job: + container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + network_mode: host + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + - name: let it cook + ansible.builtin.pause: + seconds: 10 + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + mysql.database~mysql.database::terraform@mysql.dbms->docker.engine->remote.machine: + derived_from: mysql.database metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -8870,28 +17344,6 @@ node_types: type: string default: eval: .::.requirements::[.name=host]::.target::management_address - application_port: - type: string - default: 3001 - application_address: - type: string - default: 127.0.0.1 - attributes: - management_address: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - management_port: - type: integer - default: - eval: .::application_port - capabilities: - endpoint: - type: unfurl.capabilities.Endpoint.Ansible - properties: - connection: ssh - host: - eval: .parent::management_address interfaces: Standard: operations: @@ -8904,727 +17356,402 @@ node_types: defaults: inputs: main: - resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - content: | - - #!/usr/bin/bash - set -e - export DEBIAN_FRONTEND="noninteractive" - - DBMS_PASSWORD=$1 - DBMS_PORT=$2 - - # Set password - debconf-set-selections <<< "mysql-server mysql-server/root_password password ${DBMS_PASSWORD}" - debconf-set-selections <<< "mysql-server mysql-server/root_password_again password ${DBMS_PASSWORD}" - - # Install mysql - apt-get update -y - apt-get -y install mysql-server - - # Passwordless auth - cat < /root/.my.cnf - [client] - user=root - password=${DBMS_PASSWORD} - EOF - - # Listen on all interfaces - sed -i "s/127\.0\.0\.1/0\.0\.0\.0/g" /etc/mysql/mysql.conf.d/mysqld.cnf - - # Listen on custom port - sed -i "s/# port.*/port = ${DBMS_PORT}/g" /etc/mysql/mysql.conf.d/mysqld.cnf - - # Configure any host for root - mysql -u root -e 'USE mysql; UPDATE user SET host = "%" WHERE user = "root"; FLUSH PRIVILEGES;' - mysql -u root -e 'USE mysql; DELETE FROM user WHERE user = "root" and host = "localhost"; FLUSH PRIVILEGES;' - - # Enable service - systemctl enable mysql - - # Restart service - systemctl restart mysql - destination: /tmp/install-mysql-dbms.sh - remote-exec: - - inline: - - sudo bash /tmp/install-mysql-dbms.sh {{ SELF.dbms_password }} {{ SELF.application_port }} - mysql.dbms~software.application#apt.package::ansible@*->remote.machine: - derived_from: mysql.dbms + terraform: + - required_providers: + - mysql: + source: petoju/mysql + version: 3.0.48 + ssh: + source: AndrewChubatiuk/ssh + version: 0.2.3 + data: + ssh_tunnel: + mysql: + - remote: + host: '{{ HOST.application_address }}' + port: '{{ HOST.application_port }}' + provider: + mysql: + - endpoint: ${data.ssh_tunnel.mysql.local.address} + password: '{{ HOST.dbms_password }}' + username: root + ssh: + - auth: + private_key: + content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} + server: + host: '{{ HOST.management_address }}' + port: 22 + user: '{{ SELF.os_ssh_user }}' + resource: + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + mysql.database~mysql.database::ansible@mysql.dbms->gcp.cloudsql: + derived_from: mysql.database metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + gcp_service_account_file: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: gcp_service_account_file + gcp_region: type: string default: - get_input: os_ssh_key_file - application_directory: + get_input: gcp_region + gcp_project: type: string default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name + get_input: gcp_project interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: run setup script - ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - args: - executable: /bin/bash - when: '".artifacts::apt_package::script" | eval != ""' - - name: add apt key - ansible.builtin.apt_key: - url: '{{ ".artifacts::apt_package::key" | eval }}' - keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - state: present - when: '".artifacts::apt_package::key" | eval != ""' - - name: add apt repository - ansible.builtin.apt_repository: - repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} - filename: '{{ ".artifacts::apt_package::repository" | eval }}' - state: present - when: '".artifacts::apt_package::source" | eval != ""' - - name: update apt cache - ansible.builtin.apt: - update_cache: 'yes' - - name: install dependencies - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' - state: present - when: '".artifacts::apt_package::dependencies" | eval != ""' - - name: install package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: present - environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/create.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - mode: '0755' - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/create.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - configure: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/configure.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - mode: '0755' - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/configure.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - start: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/start.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - mode: '0755' - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/start.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - stop: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/stop.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - mode: '0755' - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/stop.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - delete: - implementation: - primary: Ansible - operation_host: HOST + operation_host: ORCHESTRATOR environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/delete.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + - name: create a database + google.cloud.gcp_sql_database: + name: '{{ SELF.database_name }}' + charset: utf8 + instance: '{{ HOST.dbms_name }}' + project: '{{ SELF.gcp_project }}' + - name: install GCP CloudSQL Proxy + ansible.builtin.get_url: + url: https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.13.0/cloud-sql-proxy.linux.amd64 + dest: /tmp/gcp-cloudsql-proxy mode: '0755' - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/delete.sh + - name: forward port + ansible.builtin.shell: '/tmp/gcp-cloudsql-proxy {{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }} --credentials-file {{ SELF.gcp_service_account_file }} --port 23306 ' args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - - name: uninstall package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~software.application#apt.archive::terraform@*->remote.machine: - derived_from: mysql.dbms + executable: /usr/bin/bash + async: 30 + poll: 0 + - name: wait for port + ansible.builtin.wait_for: + host: 127.0.0.1 + port: 23306 + delay: 5 + timeout: 30 + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: 127.0.0.1 + login_password: '{{ HOST.dbms_password }}' + login_port: 23306 + login_user: root + - name: unforward port + ansible.builtin.shell: pkill -f "/tmp/gcp-cloudsql-proxy {{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }}" + args: + executable: /usr/bin/bash + mysql.database~mysql.database::terraform@mysql.dbms->gcp.cloudsql: + derived_from: mysql.database metadata: vintner_generated: 'true' + vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: + gcp_service_account_file: type: string default: - get_input: os_ssh_key_file - os_ssh_host: + get_input: gcp_service_account_file + gcp_region: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - application_directory: + get_input: gcp_region + gcp_project: type: string default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name + get_input: gcp_project interfaces: Standard: operations: configure: implementation: primary: Terraform + environment: + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file delete: implementation: primary: Terraform + environment: + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file defaults: inputs: main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + mysql: + source: petoju/mysql + version: 3.0.48 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + mysql: + - endpoint: cloudsql://{{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }} + password: '{{ HOST.dbms_password }}' + username: root resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - content: | - #!/usr/bin/bash - set -e - - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi - - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi - - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then - echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} - fi - - # Update apt cache - apt-get update -y - - # Install dependencies - if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then - apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y - fi - - # Install package - {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - DBMS_NAME="{{ SELF.dbms_name }}" - APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y - destination: /tmp/delete-mysql.dbms.sh - remote-exec: - - inline: - - sudo bash /tmp/create-mysql.dbms.sh - - sudo bash /tmp/configure-mysql.dbms.sh - - sudo bash /tmp/start-mysql.dbms.sh - - inline: - - sudo bash /tmp/stop-mysql.dbms.sh - - sudo bash /tmp/delete-mysql.dbms.sh - when: destroy - mysql.dbms~software.application#tar.archive::ansible@*->remote.machine: - derived_from: mysql.dbms + google_sql_database: + database: + - name: '{{ SELF.database_name }}' + instance: '{{ HOST.dbms_name }}' + google_sql_user: + user: + - host: '%' + instance: '{{ HOST.dbms_name }}' + name: '{{ SELF.database_name }}' + password: '{{ SELF.database_password }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${google_sql_user.user.name} + mysql.database~mysql.database::ansible@mysql.dbms->kubernetes.cluster: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + k8s_host: + type: string + default: + get_input: k8s_host + k8s_ca_cert_file: + type: string + default: + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: deploy database + block: + - name: forward port + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.dbms_name }} 23306:3306 + args: + executable: /usr/bin/bash + async: 30 + poll: 0 + - name: wait for port + ansible.builtin.wait_for: + host: 127.0.0.1 + port: 23306 + delay: 5 + timeout: 30 + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: 127.0.0.1 + login_password: '{{ HOST.dbms_password }}' + login_port: '23306' + login_user: root + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: 127.0.0.1 + login_password: '{{ HOST.dbms_password }}' + login_port: '23306' + login_user: root + always: + - name: unforward port + ansible.builtin.shell: pkill -f "port-forward service/{{ HOST.dbms_name }}" + args: + executable: /usr/bin/bash + mysql.database~mysql.database::kubernetes@mysql.dbms->kubernetes.cluster: + derived_from: mysql.database metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + k8s_host: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: os_ssh_key_file - application_directory: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") - - name: extract deployment artifact from URL in application directory - ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: |- - DBMS_NAME="{{ SELF.dbms_name }}" - APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/create.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - mode: '0755' - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/create.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - configure: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/configure.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - mode: '0755' - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/configure.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - start: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: assert management operation - ansible.builtin.fail: - dest: Management operation "start" missing - when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/start.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - mode: '0755' - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/start.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - stop: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: assert management operation - ansible.builtin.fail: - dest: Management operation "stop" missing - when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: copy management operation + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.manifest.yaml' + - name: create manifest ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/stop.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - mode: '0755' - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/stop.sh + dest: '{{ manifest.path }}' + content: '{{ job | to_yaml }}' + vars: + job: + apiVersion: batch/v1 + kind: Job + metadata: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' + spec: + template: + spec: + restartPolicy: Never + containers: + - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.database_name }}-{{ HOST.dbms_name }} + args: + executable: /usr/bin/bash + - name: cleanup + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation + - name: touch manifest + register: manifest + ansible.builtin.tempfile: + suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.manifest.yaml' + - name: create manifest ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/delete.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - mode: '0755' - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/delete.sh + dest: '{{ manifest.path }}' + content: '{{ job | to_yaml }}' + vars: + job: + apiVersion: batch/v1 + kind: Job + metadata: + name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' + spec: + template: + spec: + restartPolicy: Never + containers: + - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' + image: mysql:{{ ".artifacts::dbms_image::file" | eval }} + command: + - mysql + - '--host={{ HOST.management_address }}' + - '--port={{ HOST.management_port }}' + - '--user=root' + - '--password={{ HOST.dbms_password }}' + - '-e' + - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~software.application#tar.archive::terraform@*->remote.machine: - derived_from: mysql.dbms + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.database_name }}-{{ HOST.dbms_name }} + args: + executable: /usr/bin/bash + - name: cleanup + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + mysql.database~mysql.database::terraform@mysql.dbms->kubernetes.cluster: + derived_from: mysql.database metadata: vintner_generated: 'true' + vintner_orchestrator: unfurl properties: - os_ssh_user: + k8s_host: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: os_ssh_key_file - os_ssh_host: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - application_directory: + get_input: k8s_client_cert_file + k8s_client_key_file: type: string default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name + get_input: k8s_client_key_file interfaces: Standard: operations: @@ -9637,157 +17764,165 @@ node_types: defaults: inputs: main: - resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-mysql.dbms - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - DBMS_NAME="{{ SELF.dbms_name }}" - APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-mysql.dbms -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-mysql.dbms.sh - remote-exec: - - inline: - - sudo bash /tmp/create-mysql.dbms.sh - - sudo bash /tmp/configure-mysql.dbms.sh - - sudo bash /tmp/start-mysql.dbms.sh - - inline: - - sudo bash /tmp/stop-mysql.dbms.sh - - sudo bash /tmp/delete-mysql.dbms.sh - when: destroy - mysql.dbms~software.application#zip.archive::ansible@*->remote.machine: - derived_from: mysql.dbms + terraform: + - required_providers: + - mysql: + source: petoju/mysql + version: 3.0.48 + provider: + mysql: + - endpoint: ${terraform_data.forward_port.input} + password: '{{ HOST.dbms_password }}' + username: root + resource: + terraform_data: + forward_port: + - input: 127.0.0.1:23306 + provisioner: + local-exec: + command: |- + (nohup kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.dbms_name }} 23306:3306 > /dev/null 2>&1 &) + sleep 5s + interpreter: + - /bin/bash + - '-c' + unforward_port: + - depends_on: + - mysql_grant.user + provisioner: + local-exec: + command: pkill -f "port-forward service/{{ HOST.dbms_name }}" + interpreter: + - /bin/bash + - '-c' + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + mysql.database~mysql.database::ansible@mysql.dbms->local.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install pip + ansible.builtin.apt: + name: python3-pip + state: present + - name: install pymysql + ansible.builtin.pip: + name: pymysql + state: present + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: delete user (with privileges) + community.mysql.mysql_user: + state: absent + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: delete database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + state: absent + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + mysql.database~mysql.database::terraform@mysql.dbms->local.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - mysql: + source: petoju/mysql + version: 3.0.48 + provider: + mysql: + - endpoint: '{{ HOST.application_address }}:{{ HOST.application_port }}' + password: '{{ HOST.dbms_password }}' + username: root + resource: + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + mysql.database~mysql.database::ansible@mysql.dbms->remote.machine: + derived_from: mysql.database metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -9800,14 +17935,6 @@ node_types: type: string default: get_input: os_ssh_key_file - application_directory: - type: string - default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name interfaces: Standard: operations: @@ -9822,90 +17949,36 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies + - name: install pip ansible.builtin.apt: - name: unzip - update_cache: 'yes' - - name: create application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: |- - DBMS_NAME="{{ SELF.dbms_name }}" - APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/create.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - mode: '0755' - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/create.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - configure: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/configure.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - mode: '0755' - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/configure.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + name: python3-pip + state: present + - name: install pymysql + ansible.builtin.pip: + name: pymysql + state: present + - name: create database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: create user (with privileges) + community.mysql.mysql_user: + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - start: + delete: implementation: primary: Ansible operation_host: HOST @@ -9916,125 +17989,222 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: assert management operation - ansible.builtin.fail: - dest: Management operation "start" missing - when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/start.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - mode: '0755' - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/start.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete user (with privileges) + community.mysql.mysql_user: + state: absent + name: '{{ SELF.database_user }}' + password: '{{ SELF.database_password }}' + host: '%' + priv: '*.*:ALL' + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root + - name: delete database + community.mysql.mysql_db: + name: '{{ SELF.database_name }}' + state: absent + login_host: '{{ HOST.application_address }}' + login_password: '{{ HOST.dbms_password }}' + login_port: '{{ HOST.application_port }}' + login_user: root playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - stop: + mysql.database~mysql.database::terraform@mysql.dbms->remote.machine: + derived_from: mysql.database + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - mysql: + source: petoju/mysql + version: 3.0.48 + ssh: + source: AndrewChubatiuk/ssh + version: 0.2.3 + data: + ssh_tunnel: + mysql: + - remote: + host: '{{ HOST.application_address }}' + port: '{{ HOST.application_port }}' + provider: + mysql: + - endpoint: ${data.ssh_tunnel.mysql.local.address} + password: '{{ HOST.dbms_password }}' + username: root + ssh: + - auth: + private_key: + content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} + server: + host: '{{ HOST.management_address }}' + port: 22 + user: '{{ SELF.os_ssh_user }}' + resource: + mysql_database: + database: + - name: '{{ SELF.database_name }}' + mysql_user: + user: + - host: '%' + plaintext_password: '{{ SELF.database_password }}' + user: '{{ SELF.database_user }}' + mysql_grant: + user: + - database: '{{ SELF.database_name }}' + host: '%' + table: '*' + privileges: + - ALL + user: ${mysql_user.user.user} + minio.server~service.application#docker.image::ansible@docker.engine->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: assert management operation - ansible.builtin.fail: - dest: Management operation "stop" missing - when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: copy management operation + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + state: absent + minio.server~service.application#docker.image::compose@docker.engine->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/stop.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - mode: '0755' - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/stop.sh + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' + executable: /usr/bin/bash delete: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.compose.yaml' + - name: create compose ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/delete.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - mode: '0755' - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/delete.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.dbms~software.application#zip.archive::terraform@*->remote.machine: - derived_from: mysql.dbms + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.application_name }}' + services: + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + environment: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + minio.server~service.application#docker.image::terraform@docker.engine->local.machine: + derived_from: minio.server metadata: vintner_generated: 'true' - properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - application_directory: + vintner_orchestrator: unfurl + attributes: + application_address: type: string - default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name + default: 127.0.0.1 interfaces: Standard: operations: @@ -10047,222 +18217,104 @@ node_types: defaults: inputs: main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + required_version: '>= 0.14.0' + provider: + docker: + - host: unix:///var/run/docker.sock resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-mysql.dbms - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - DBMS_NAME="{{ SELF.dbms_name }}" - APPLICATION_NAME="{{ SELF.application_name }}" - DBMS_PASSWORD="{{ SELF.dbms_password }}" - DBMS_SSL_MODE="{{ SELF.dbms_ssl_mode }}" - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-mysql.dbms {{ ".artifacts::zip_archive::file" | eval }} - fi - - # Extract deployment artifact - unzip /tmp/artifact-mysql.dbms -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-mysql.dbms.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-mysql.dbms.sh - remote-exec: - - inline: - - sudo bash /tmp/create-mysql.dbms.sh - - sudo bash /tmp/configure-mysql.dbms.sh - - sudo bash /tmp/start-mysql.dbms.sh - - inline: - - sudo bash /tmp/stop-mysql.dbms.sh - - sudo bash /tmp/delete-mysql.dbms.sh - when: destroy - mysql.database~mysql.database::ansible@mysql.dbms->docker.engine->local.machine: - derived_from: mysql.database + docker_container: + application: + - env: + - MINIO_ROOT_USER={{ SELF.access_key }} + - MINIO_ROOT_PASSWORD={{ SELF.secret_key }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' + minio.server~service.application#docker.image::ansible@docker.engine->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + attributes: + application_address: + type: string + default: 127.0.0.1 interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: get dbms container info - community.docker.docker_container_info: - name: '{{ HOST.dbms_name }}' - register: dbms_container_info - - name: create database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: create user (with privileges) - community.mysql.mysql_user: - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root + - name: wait for ssh + wait_for_connection: + - name: start container + community.docker.docker_container: + name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' + network_mode: host + env: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: delete user (with privileges) - community.mysql.mysql_user: - state: absent - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: delete database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' + - name: wait for ssh + wait_for_connection: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.application_name }}' state: absent - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - mysql.database~mysql.database::compose@mysql.dbms->docker.engine->local.machine: - derived_from: mysql.database + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + minio.server~service.application#docker.image::compose@docker.engine->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl + properties: + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 interfaces: Standard: operations: @@ -10276,38 +18328,28 @@ node_types: - name: touch compose register: compose ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + suffix: '{{ SELF.application_name }}.compose.yaml' - name: create compose ansible.builtin.copy: dest: '{{ compose.path }}' content: '{{ manifest | to_yaml }}' vars: manifest: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + name: '{{ SELF.application_name }}' services: - job: - container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - image: mysql:{{ HOST.dbms_version }} + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' network_mode: host - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; + environment: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' - name: apply compose ansible.builtin.shell: docker compose -f {{ compose.path }} up -d args: executable: /usr/bin/bash - - name: give job some time - ansible.builtin.pause: - seconds: 10 - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down - args: - executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' delete: implementation: primary: Ansible @@ -10318,56 +18360,228 @@ node_types: - name: touch compose register: compose ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' + suffix: '{{ SELF.application_name }}.compose.yaml' - name: create compose ansible.builtin.copy: dest: '{{ compose.path }}' content: '{{ manifest | to_yaml }}' vars: manifest: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' + name: '{{ SELF.application_name }}' services: - job: - container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - image: mysql:{{ HOST.dbms_version }} + application: + container_name: '{{ SELF.application_name }}' + image: '{{ ".artifacts::docker_image::file" | eval }}' network_mode: host - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + environment: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + minio.server~service.application#docker.image::terraform@docker.engine->remote.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + terraform: + - required_providers: + - docker: + source: kreuzwerker/docker + version: 3.0.2 + provider: + docker: + - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 + ssh_opts: + - '-i' + - '{{ SELF.os_ssh_key_file }}' + - '-o' + - IdentitiesOnly=yes + - '-o' + - BatchMode=yes + - '-o' + - UserKnownHostsFile=/dev/null + - '-o' + - StrictHostKeyChecking=no + resource: + docker_container: + application: + - env: + - MINIO_ROOT_USER={{ SELF.access_key }} + - MINIO_ROOT_PASSWORD={{ SELF.secret_key }} + image: ${docker_image.image.image_id} + name: '{{ SELF.application_name }}' + network_mode: host + docker_image: + image: + - name: '{{ ".artifacts::docker_image::file" | eval }}' + minio.server~service.application#docker.image::ansible@gcp.cloudrun: + derived_from: minio.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: touch service + register: service + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.service.yaml' + - name: create service + ansible.builtin.copy: + dest: '{{ service.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + apiVersion: serving.knative.dev/v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + labels: + cloud.googleapis.com/location: '{{ SELF.gcp_region }}' + annotations: + run.googleapis.com/ingress: all + spec: + template: + spec: + containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + ports: + - name: http1 + containerPort: '{{ SELF.application_port }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + - name: apply service + ansible.builtin.shell: gcloud run services replace {{ service.path }} --quiet + args: + executable: /bin/bash + - name: touch policy + register: policy + ansible.builtin.tempfile: + suffix: '{{ SELF.application_name }}.policy.yaml' + - name: fill policy + ansible.builtin.copy: + dest: '{{ policy.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + bindings: + - members: + - allUsers + role: roles/run.invoker + - name: apply policy + ansible.builtin.shell: gcloud run services set-iam-policy {{ SELF.application_name }} {{ policy.path }} --region {{ SELF.gcp_region }} --quiet + args: + executable: /bin/bash + - name: describe service + register: service_description + ansible.builtin.shell: gcloud run services describe {{ SELF.application_name }} --region {{ SELF.gcp_region }} --quiet --format=json + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ (service_description.stdout | from_json ).status.url[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ (service_description.stdout | from_json ).status.url[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address | trim }}' + application_endpoint: '{{ outputs.application_endpoint | trim }}' + outputs: + application_address: + application_endpoint: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} args: - executable: /usr/bin/bash - - name: give job some time - ansible.builtin.pause: - seconds: 10 - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud run services delete {{ SELF.application_name }} --region {{ SELF.gcp_region }} --quiet args: - executable: /usr/bin/bash - mysql.database~mysql.database::terraform@mysql.dbms->docker.engine->local.machine: - derived_from: mysql.database + executable: /bin/bash + minio.server~service.application#docker.image::terraform@gcp.cloudrun: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + gcp_service_account_file: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: gcp_service_account_file + gcp_region: type: string default: - get_input: os_ssh_key_file - os_ssh_host: + get_input: gcp_region + gcp_project: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address + get_input: gcp_project interfaces: Standard: operations: @@ -10378,165 +18592,180 @@ node_types: implementation: primary: Terraform defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint inputs: main: terraform: - required_providers: - - mysql: - source: petoju/mysql - version: 3.0.48 + - google: + source: hashicorp/google + version: 5.39.1 provider: - mysql: - - endpoint: 127.0.0.1:{{ HOST.management_port }} - password: '{{ HOST.dbms_password }}' - username: root + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: ${substr(google_cloud_run_v2_service.application.uri, 8, -1)} + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://${substr(google_cloud_run_v2_service.application.uri, 8, -1)}:443' resource: - mysql_database: - database: - - name: '{{ SELF.database_name }}' - mysql_user: - user: - - host: '%' - plaintext_password: '{{ SELF.database_password }}' - user: '{{ SELF.database_user }}' - mysql_grant: - user: - - database: '{{ SELF.database_name }}' - host: '%' - table: '*' - privileges: - - ALL - user: ${mysql_user.user.user} - mysql.database~mysql.database::ansible@mysql.dbms->docker.engine->remote.machine: - derived_from: mysql.database + google_cloud_run_v2_service: + application: + - ingress: INGRESS_TRAFFIC_ALL + location: '{{ SELF.gcp_region }}' + name: '{{ SELF.application_name }}' + template: + - containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + ports: + - name: http1 + container_port: '{{ SELF.application_port }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + google_cloud_run_service_iam_binding: + application: + - location: '{{ SELF.gcp_region }}' + members: + - allUsers + role: roles/run.invoker + service: '{{ SELF.application_name }}' + minio.server~service.application#docker.image::ansible@kubernetes.cluster: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + k8s_host: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: os_ssh_key_file + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file + attributes: + application_address: + type: string + default: + eval: .::application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST + operation_host: ORCHESTRATOR environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: install pip - ansible.builtin.apt: - name: python3-pip - state: present - - name: install pymysql - ansible.builtin.pip: - name: pymysql - state: present - - name: get dbms container info - community.docker.docker_container_info: - name: '{{ HOST.dbms_name }}' - register: dbms_container_info - - name: forward port - when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" - community.docker.docker_container: - name: '{{ HOST.dbms_name }}-port-forward' - image: nicolaka/netshoot:v0.13 - command: socat TCP6-LISTEN:3306,fork TCP:{{ HOST.dbms_name }}:3306 - ports: - - '{{ HOST.application_port }}:3306' - - name: create forwarding network - community.docker.docker_network: - name: '{{ HOST.dbms_name }}-port-forward' - connected: - - '{{ HOST.dbms_name }}-port-forward' - - '{{ HOST.dbms_name }}' - when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" - - name: create database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: create user (with privileges) - community.mysql.mysql_user: - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: unforward port - when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" - community.docker.docker_container: - name: '{{ HOST.dbms_name }}-port-forward' - state: absent - - name: remove forwarding network - community.docker.docker_network: - name: '{{ HOST.dbms_name }}-port-forward' - state: absent - when: "'host' not in dbms_container_info.container.NetworkSettings.Networks" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' + - name: create deployment + kubernetes.core.k8s: + wait: true + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.application_name }}' + template: + metadata: + labels: + app: '{{ SELF.application_name }}' + spec: + containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + name: '{{ SELF.application_name }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + ports: + - containerPort: '{{ SELF.application_port }}' + - name: create service + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP delete: implementation: primary: Ansible - operation_host: HOST + operation_host: ORCHESTRATOR environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: delete user (with privileges) - community.mysql.mysql_user: + - name: delete service + kubernetes.core.k8s: state: absent - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: delete database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' + api_version: v1 + kind: Service + namespace: default + name: '{{ SELF.application_name }}' + - name: delete deployment + kubernetes.core.k8s: state: absent - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.database~mysql.database::compose@mysql.dbms->docker.engine->remote.machine: - derived_from: mysql.database + api_version: app/v1 + kind: Deployment + namespace: default + name: '{{ SELF.application_name }}' + minio.server~service.application#docker.image::kubernetes@kubernetes.cluster: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - os_ssh_host: + attributes: + application_address: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address + eval: .::application_name interfaces: Standard: operations: @@ -10547,45 +18776,65 @@ node_types: inputs: playbook: q: - - name: touch compose - register: compose + - name: touch manifest + register: manifest ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' - - name: create compose + suffix: '{{ SELF.application_name }}.application.manifest.yaml' + - name: create manifest ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} vars: - manifest: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - services: - job: - container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - image: mysql:{{ HOST.dbms_version }} - network_mode: host - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.application_name }}' + template: + metadata: + labels: + app: '{{ SELF.application_name }}' + spec: + containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + name: '{{ SELF.application_name }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + ports: + - containerPort: '{{ SELF.application_port }}' + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} args: executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - - name: give job some time - ansible.builtin.pause: - seconds: 10 - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} rollout status deployment/{{ SELF.application_name }} --timeout 60s args: executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' delete: implementation: primary: Ansible @@ -10593,282 +18842,162 @@ node_types: inputs: playbook: q: - - name: touch compose - register: compose + - name: touch manifest + register: manifest ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.compose.yaml' - - name: create compose + suffix: '{{ SELF.application_name }}.application.manifest.yaml' + - name: create manifest ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} vars: - manifest: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - services: - job: - container_name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}-database-job' - image: mysql:{{ HOST.dbms_version }} - network_mode: host - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d - args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - - name: give job some time - ansible.builtin.pause: - seconds: 10 - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down - args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - mysql.database~mysql.database::terraform@mysql.dbms->docker.engine->remote.machine: - derived_from: mysql.database - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform - delete: - implementation: - primary: Terraform - defaults: - inputs: - main: - terraform: - - required_providers: - - mysql: - source: petoju/mysql - version: 3.0.48 - ssh: - source: AndrewChubatiuk/ssh - version: 0.2.3 - data: - ssh_tunnel: - mysql: - - remote: - host: '{{ HOST.application_address }}' - port: '{{ HOST.application_port }}' - provider: - mysql: - - endpoint: ${data.ssh_tunnel.mysql.local.address} - password: '{{ HOST.dbms_password }}' - username: root - ssh: - - auth: - private_key: - content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} - server: - host: '{{ HOST.management_address }}' - port: 22 - user: '{{ SELF.os_ssh_user }}' - resource: - mysql_database: - database: - - name: '{{ SELF.database_name }}' - mysql_user: - user: - - host: '%' - plaintext_password: '{{ SELF.database_password }}' - user: '{{ SELF.database_user }}' - mysql_grant: - user: - - database: '{{ SELF.database_name }}' - host: '%' - table: '*' - privileges: - - ALL - user: ${mysql_user.user.user} - mysql.database~mysql.database::ansible@mysql.dbms->gcp.cloudsql: - derived_from: mysql.database + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.application_name }}' + template: + metadata: + labels: + app: '{{ SELF.application_name }}' + spec: + containers: + - image: '{{ ".artifacts::docker_image::file" | eval }}' + name: '{{ SELF.application_name }}' + env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + ports: + - containerPort: '{{ SELF.application_port }}' + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP + - name: unapply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + args: + executable: /usr/bin/bash + minio.server~service.application#docker.image::terraform@kubernetes.cluster: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: + k8s_host: type: string default: - get_input: gcp_region - gcp_project: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: gcp_project - interfaces: - Standard: - operations: - create: - implementation: - primary: Ansible - operation_host: ORCHESTRATOR - environment: - GCP_SERVICE_ACCOUNT_FILE: - eval: .::gcp_service_account_file - GCP_AUTH_KIND: serviceaccount - inputs: - playbook: - q: - - name: create a database - google.cloud.gcp_sql_database: - name: '{{ SELF.database_name }}' - charset: utf8 - instance: '{{ HOST.dbms_name }}' - project: '{{ SELF.gcp_project }}' - - name: install GCP CloudSQL Proxy - ansible.builtin.get_url: - url: https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.13.0/cloud-sql-proxy.linux.amd64 - dest: /tmp/gcp-cloudsql-proxy - mode: '0755' - - name: forward port - ansible.builtin.shell: '/tmp/gcp-cloudsql-proxy {{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }} --credentials-file {{ SELF.gcp_service_account_file }} --port 23306 ' - args: - executable: /usr/bin/bash - async: 30 - poll: 0 - - name: wait for port - ansible.builtin.wait_for: - host: 127.0.0.1 - port: 23306 - delay: 5 - timeout: 30 - - name: create user (with privileges) - community.mysql.mysql_user: - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: 127.0.0.1 - login_password: '{{ HOST.dbms_password }}' - login_port: 23306 - login_user: root - - name: unforward port - ansible.builtin.shell: pkill -f "/tmp/gcp-cloudsql-proxy {{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }}" - args: - executable: /usr/bin/bash - mysql.database~mysql.database::terraform@mysql.dbms->gcp.cloudsql: - derived_from: mysql.database - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - gcp_service_account_file: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: k8s_client_cert_file + k8s_client_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: k8s_client_key_file + attributes: + application_address: type: string default: - get_input: gcp_project + eval: .::application_name interfaces: Standard: operations: configure: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file delete: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file defaults: inputs: main: terraform: - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - mysql: - source: petoju/mysql - version: 3.0.48 + - kubernetes: + source: hashicorp/kubernetes + version: 2.31.0 + required_version: '>= 0.14.0' provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - mysql: - - endpoint: cloudsql://{{ SELF.gcp_project }}:{{ SELF.gcp_region }}:{{ HOST.dbms_name }} - password: '{{ HOST.dbms_password }}' - username: root + kubernetes: + - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} + client_key: ${file("{{ SELF.k8s_client_key_file }}")} + cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} + host: '{{ SELF.k8s_host }}' resource: - google_sql_database: - database: - - name: '{{ SELF.database_name }}' - instance: '{{ HOST.dbms_name }}' - google_sql_user: - user: - - host: '%' - instance: '{{ HOST.dbms_name }}' - name: '{{ SELF.database_name }}' - password: '{{ SELF.database_password }}' - mysql_grant: - user: - - database: '{{ SELF.database_name }}' - host: '%' - table: '*' - privileges: - - ALL - user: ${google_sql_user.user.name} - mysql.database~mysql.database::ansible@mysql.dbms->kubernetes.cluster: - derived_from: mysql.database + kubernetes_deployment_v1: + application: + - metadata: + - name: '{{ SELF.application_name }}' + spec: + - selector: + - match_labels: + app: '{{ SELF.application_name }}' + template: + - metadata: + - labels: + app: '{{ SELF.application_name }}' + spec: + - container: + - env: + - name: MINIO_ROOT_USER + value: '"{{ SELF.access_key }}"' + - name: MINIO_ROOT_PASSWORD + value: '"{{ SELF.secret_key }}"' + image: '{{ ".artifacts::docker_image::file" | eval }}' + name: '{{ SELF.application_name }}' + port: + - container_port: '{{ SELF.application_port }}' + kubernetes_service_v1: + application: + - metadata: + - name: '{{ SELF.application_name }}' + spec: + - port: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + target_port: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP + minio.server~service.application#tar.archive::ansible@*->local.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: + application_directory: type: string default: - get_input: k8s_client_key_file + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -10879,115 +19008,157 @@ node_types: inputs: playbook: q: - - name: deploy database - block: - - name: forward port - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.dbms_name }} 23306:3306 - args: - executable: /usr/bin/bash - async: 30 - poll: 0 - - name: wait for port - ansible.builtin.wait_for: - host: 127.0.0.1 - port: 23306 - delay: 5 - timeout: 30 - - name: create database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' - login_host: 127.0.0.1 - login_password: '{{ HOST.dbms_password }}' - login_port: '23306' - login_user: root - - name: create user (with privileges) - community.mysql.mysql_user: - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: 127.0.0.1 - login_password: '{{ HOST.dbms_password }}' - login_port: '23306' - login_user: root - always: - - name: unforward port - ansible.builtin.shell: pkill -f "port-forward service/{{ HOST.dbms_name }}" - args: - executable: /usr/bin/bash - mysql.database~mysql.database::kubernetes@mysql.dbms->kubernetes.cluster: - derived_from: mysql.database - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: - type: string - default: - get_input: k8s_client_key_file - interfaces: - Standard: - operations: - create: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: touch manifest - register: manifest - ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.manifest.yaml' - - name: create manifest + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: '{{ job | to_yaml }}' - vars: - job: - apiVersion: batch/v1 - kind: Job - metadata: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' - spec: - template: - spec: - restartPolicy: Never - containers: - - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' - image: mysql:{{ HOST.dbms_version }} - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - CREATE DATABASE IF NOT EXISTS {{ SELF.database_name }}; CREATE USER IF NOT EXISTS '{{ SELF.database_user }}'@'%' IDENTIFIED BY '{{ SELF.database_password }}'; GRANT ALL PRIVILEGES ON *.* TO '{{ SELF.database_user }}'@'%'; - - name: apply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} - args: - executable: /usr/bin/bash - - name: wait for deployment - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.database_name }}-{{ HOST.dbms_name }} + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: - executable: /usr/bin/bash - - name: cleanup - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: - executable: /usr/bin/bash + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped delete: implementation: primary: Ansible @@ -10995,69 +19166,46 @@ node_types: inputs: playbook: q: - - name: touch manifest - register: manifest - ansible.builtin.tempfile: - suffix: '{{ SELF.database_name }}-{{ HOST.dbms_name }}.database.manifest.yaml' - - name: create manifest + - name: copy management operation ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: '{{ job | to_yaml }}' - vars: - job: - apiVersion: batch/v1 - kind: Job - metadata: - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' - spec: - template: - spec: - restartPolicy: Never - containers: - - name: '{{ SELF.database_name }}-{{ HOST.dbms_name }}' - image: mysql:{{ HOST.dbms_version }} - command: - - mysql - - '--host={{ HOST.management_address }}' - - '--port={{ HOST.management_port }}' - - '--user=root' - - '--password={{ HOST.dbms_password }}' - - '-e' - - DROP USER IF EXISTS '{{ SELF.database_user }}'@'%'; DROP DATABASE IF EXISTS {{ SELF.database_name }}; - - name: apply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} - args: - executable: /usr/bin/bash - - name: wait for deployment - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} wait --for=condition=complete --timeout=30s job/{{ SELF.database_name }}-{{ HOST.dbms_name }} - args: - executable: /usr/bin/bash - - name: cleanup - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: - executable: /usr/bin/bash - mysql.database~mysql.database::terraform@mysql.dbms->kubernetes.cluster: - derived_from: mysql.database - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + minio.server~service.application#tar.archive::terraform@*->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + properties: + application_directory: type: string default: - get_input: k8s_client_key_file + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -11070,55 +19218,168 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - mysql: - source: petoju/mysql - version: 3.0.48 - provider: - mysql: - - endpoint: ${terraform_data.forward_port.input} - password: '{{ HOST.dbms_password }}' - username: root resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-minio.server.sh terraform_data: - forward_port: - - input: 127.0.0.1:23306 - provisioner: - local-exec: - command: |- - (nohup kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} port-forward service/{{ HOST.dbms_name }} 23306:3306 > /dev/null 2>&1 &) - sleep 5s - interpreter: - - /bin/bash - - '-c' - unforward_port: + local: - depends_on: - - mysql_grant.user + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: local-exec: - command: pkill -f "port-forward service/{{ HOST.dbms_name }}" - interpreter: - - /bin/bash - - '-c' - mysql_database: - database: - - name: '{{ SELF.database_name }}' - mysql_user: - user: - - host: '%' - plaintext_password: '{{ SELF.database_password }}' - user: '{{ SELF.database_user }}' - mysql_grant: - user: - - database: '{{ SELF.database_name }}' - host: '%' - table: '*' - privileges: - - ALL - user: ${mysql_user.user.user} - mysql.database~mysql.database::ansible@mysql.dbms->remote.machine: - derived_from: mysql.database + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~service.application#tar.archive::ansible@*->remote.machine: + derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl @@ -11131,6 +19392,14 @@ node_types: type: string default: get_input: os_ssh_key_file + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -11145,256 +19414,252 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install pip - ansible.builtin.apt: - name: python3-pip - state: present - - name: install pymysql - ansible.builtin.pip: - name: pymysql - state: present - - name: create database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: create user (with privileges) - community.mysql.mysql_user: - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - delete: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: delete user (with privileges) - community.mysql.mysql_user: - state: absent - name: '{{ SELF.database_user }}' - password: '{{ SELF.database_password }}' - host: '%' - priv: '*.*:ALL' - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - - name: delete database - community.mysql.mysql_db: - name: '{{ SELF.database_name }}' - state: absent - login_host: '{{ HOST.application_address }}' - login_password: '{{ HOST.dbms_password }}' - login_port: '{{ HOST.application_port }}' - login_user: root - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - mysql.database~mysql.database::terraform@mysql.dbms->remote.machine: - derived_from: mysql.database - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform - delete: - implementation: - primary: Terraform - defaults: - inputs: - main: - terraform: - - required_providers: - - mysql: - source: petoju/mysql - version: 3.0.48 - ssh: - source: AndrewChubatiuk/ssh - version: 0.2.3 - data: - ssh_tunnel: - mysql: - - remote: - host: '{{ HOST.application_address }}' - port: '{{ HOST.application_port }}' - provider: - mysql: - - endpoint: ${data.ssh_tunnel.mysql.local.address} - password: '{{ HOST.dbms_password }}' - username: root - ssh: - - auth: - private_key: - content: ${file(pathexpand("{{ SELF.os_ssh_key_file }}"))} - server: - host: '{{ HOST.management_address }}' - port: 22 - user: '{{ SELF.os_ssh_user }}' - resource: - mysql_database: - database: - - name: '{{ SELF.database_name }}' - mysql_user: - user: - - host: '%' - plaintext_password: '{{ SELF.database_password }}' - user: '{{ SELF.database_user }}' - mysql_grant: - user: - - database: '{{ SELF.database_name }}' - host: '%' - table: '*' - privileges: - - ALL - user: ${mysql_user.user.user} - minio.server~service.application#docker.image::ansible@docker.engine->local.machine: - derived_from: minio.server - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - attributes: - application_address: - type: string - default: 127.0.0.1 - interfaces: - Standard: - operations: - create: + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: start container - community.docker.docker_container: - name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' - network_mode: host - env: {} - delete: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: stop container - community.docker.docker_container: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: name: '{{ SELF.application_name }}' - state: absent - minio.server~service.application#docker.image::compose@docker.engine->local.machine: - derived_from: minio.server - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - attributes: - application_address: - type: string - default: 127.0.0.1 - interfaces: - Standard: - operations: - create: + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.compose.yaml' - - name: create compose + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.application_name }}' - services: - application: - container_name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' - network_mode: host - environment: {} - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: - executable: /usr/bin/bash + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.compose.yaml' - - name: create compose + - name: wait for ssh + wait_for_connection: + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.application_name }}' - services: - application: - container_name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' - network_mode: host - environment: {} - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: - executable: /usr/bin/bash - minio.server~service.application#docker.image::terraform@docker.engine->local.machine: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + minio.server~service.application#tar.archive::terraform@*->remote.machine: derived_from: minio.server - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - attributes: - application_address: + metadata: + vintner_generated: 'true' + properties: + os_ssh_user: type: string - default: 127.0.0.1 + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -11407,133 +19672,335 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - docker: - source: kreuzwerker/docker - version: 3.0.2 - required_version: '>= 0.14.0' - provider: - docker: - - host: unix:///var/run/docker.sock resource: - docker_container: - application: - - env: [] - image: ${docker_image.image.image_id} - name: '{{ SELF.application_name }}' - network_mode: host - docker_image: - image: - - name: '{{ ".artifacts::docker_image::file" | eval }}' - minio.server~service.application#docker.image::ansible@docker.engine->remote.machine: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-minio.server.sh + remote-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~service.application#zip.archive::ansible@*->local.machine: derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: + application_directory: type: string default: - get_input: os_ssh_key_file - attributes: - application_address: - type: string - default: 127.0.0.1 + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: create service + ansible.builtin.copy: + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: start container - community.docker.docker_container: - name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' - network_mode: host - env: {} - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - delete: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: stop container - community.docker.docker_container: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: name: '{{ SELF.application_name }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - minio.server~service.application#docker.image::compose@docker.engine->remote.machine: - derived_from: minio.server - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - properties: - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - attributes: - application_address: - type: string - default: 127.0.0.1 - interfaces: - Standard: - operations: - create: + state: started + enabled: 'yes' + daemon_reload: 'yes' + stop: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.compose.yaml' - - name: create compose + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.application_name }}' - services: - application: - container_name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' - network_mode: host - environment: {} - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped delete: implementation: primary: Ansible @@ -11541,51 +20008,46 @@ node_types: inputs: playbook: q: - - name: touch compose - register: compose - ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.compose.yaml' - - name: create compose + - name: copy management operation ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - name: '{{ SELF.application_name }}' - services: - application: - container_name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' - network_mode: host - environment: {} - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: - executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - minio.server~service.application#docker.image::terraform@docker.engine->remote.machine: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + minio.server~service.application#zip.archive::terraform@*->local.machine: derived_from: minio.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: + application_directory: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address - attributes: - application_address: - type: string - default: 127.0.0.1 + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -11598,166 +20060,452 @@ node_types: defaults: inputs: main: - terraform: - - required_providers: - - docker: - source: kreuzwerker/docker - version: 3.0.2 - provider: - docker: - - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 - ssh_opts: - - '-i' - - '{{ SELF.os_ssh_key_file }}' - - '-o' - - IdentitiesOnly=yes - - '-o' - - BatchMode=yes - - '-o' - - UserKnownHostsFile=/dev/null - - '-o' - - StrictHostKeyChecking=no resource: - docker_container: - application: - - env: [] - image: ${docker_image.image.image_id} - name: '{{ SELF.application_name }}' - network_mode: host - docker_image: - image: - - name: '{{ ".artifacts::docker_image::file" | eval }}' - minio.server~service.application#docker.image::ansible@gcp.cloudrun: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_service: + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + filename: /etc/systemd/system/{{ SELF.application_name }}.service + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-minio.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + filename: /tmp/delete-minio.server.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_service + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~service.application#zip.archive::ansible@*->remote.machine: derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: touch service - register: service - ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.service.yaml' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: create service ansible.builtin.copy: - dest: '{{ service.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - apiVersion: serving.knative.dev/v1 - kind: Service - metadata: - name: '{{ SELF.application_name }}' - labels: - cloud.googleapis.com/location: '{{ SELF.gcp_region }}' - annotations: - run.googleapis.com/ingress: all - spec: - template: - spec: - containers: - - image: '{{ ".artifacts::docker_image::file" | eval }}' - ports: - - name: http1 - containerPort: '{{ SELF.application_port }}' - env: [] - - name: apply service - ansible.builtin.shell: gcloud run services replace {{ service.path }} --quiet + dest: /etc/systemd/system/{{ SELF.application_name }}.service + content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + - name: enable service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + configure: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: touch policy - register: policy - ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.policy.yaml' - - name: fill policy + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + start: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ policy.path }}' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - bindings: - - members: - - allUsers - role: roles/run.invoker - - name: apply policy - ansible.builtin.shell: gcloud run services set-iam-policy {{ SELF.application_name }} {{ policy.path }} --region {{ SELF.gcp_region }} --quiet + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: describe service - register: service_description - ansible.builtin.shell: gcloud run services describe {{ SELF.application_name }} --region {{ SELF.gcp_region }} --quiet --format=json + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: start service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: started + enabled: 'yes' + daemon_reload: 'yes' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + stop: + implementation: + primary: Ansible + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ (service_description.stdout | from_json ).status.url[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ (service_description.stdout | from_json ).status.url[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: - application_address: '{{ outputs.application_address | trim }}' - application_endpoint: '{{ outputs.application_endpoint | trim }}' - outputs: - application_address: - application_endpoint: + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: stop service + ansible.builtin.systemd: + name: '{{ SELF.application_name }}' + state: stopped + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud run services delete {{ SELF.application_name }} --region {{ SELF.gcp_region }} --quiet + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - minio.server~service.application#docker.image::terraform@gcp.cloudrun: + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: delete systemd service + ansible.builtin.file: + path: /etc/systemd/system/{{ SELF.application_name }}.service + state: absent + - name: reload daemon + ansible.builtin.systemd: + daemon_reload: true + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + minio.server~service.application#zip.archive::terraform@*->remote.machine: derived_from: minio.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - gcp_service_account_file: + os_ssh_user: type: string default: - get_input: gcp_service_account_file - gcp_region: + get_input: os_ssh_user + os_ssh_key_file: type: string default: - get_input: gcp_region - gcp_project: + get_input: os_ssh_key_file + os_ssh_host: type: string default: - get_input: gcp_project + eval: .::.requirements::[.name=host]::.target::management_address + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -11768,172 +20516,176 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: ${substr(google_cloud_run_v2_service.application.uri, 8, -1)} - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://${substr(google_cloud_run_v2_service.application.uri, 8, -1)}:443' resource: - google_cloud_run_v2_service: - application: - - ingress: INGRESS_TRAFFIC_ALL - location: '{{ SELF.gcp_region }}' - name: '{{ SELF.application_name }}' - template: - - containers: - - image: '{{ ".artifacts::docker_image::file" | eval }}' - ports: - - name: http1 - container_port: '{{ SELF.application_port }}' - env: [] - google_cloud_run_service_iam_binding: - application: - - location: '{{ SELF.gcp_region }}' - members: - - allUsers - role: roles/run.invoker - service: '{{ SELF.application_name }}' - minio.server~service.application#docker.image::ansible@kubernetes.cluster: + terraform_data: + vm: + - connection: + - host: '{{ SELF.os_ssh_host }}' + private_key: ${file("{{ SELF.os_ssh_key_file }}")} + type: ssh + user: '{{ SELF.os_ssh_user }}' + provisioner: + file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + destination: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + - content: | + [Unit] + After=network.target + + [Service] + Type=simple + ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" + WorkingDirectory={{ SELF.application_directory }} + EnvironmentFile={{ SELF.application_directory }}/.env + + [Install] + WantedBy=multi-user.target + destination: /etc/systemd/system/{{ SELF.application_name }}.service + - content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-minio.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Reload systemd daemon + systemctl daemon-reload + + # Enable service + systemctl enable {{ SELF.application_name }} + destination: /tmp/create-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + destination: /tmp/configure-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Start service + systemctl start {{ SELF.application_name }} + destination: /tmp/start-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + + # Stop service + systemctl stop {{ SELF.application_name }} + destination: /tmp/stop-minio.server.sh + - content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Delete systemd service + rm -f /etc/systemd/system/{{ SELF.application_name }}.service + + # Reload system daemon + systemctl daemon-reload + destination: /tmp/delete-minio.server.sh + remote-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~service.application#zip.archive::ansible@gcp.appengine: derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: - type: string - default: - get_input: k8s_client_cert_file - k8s_client_key_file: + gcp_service_account_file: type: string default: - get_input: k8s_client_key_file - attributes: - application_address: + get_input: gcp_service_account_file + gcp_region: type: string default: - eval: .::application_name - interfaces: - Standard: - operations: - create: - implementation: - primary: Ansible - operation_host: ORCHESTRATOR - environment: - K8S_AUTH_HOST: - eval: .::k8s_host - K8S_AUTH_SSL_CA_CERT: - eval: .::k8s_ca_cert_file - K8S_AUTH_CERT_FILE: - eval: .::k8s_client_cert_file - K8S_AUTH_KEY_FILE: - eval: .::k8s_client_key_file - inputs: - playbook: - q: - - name: create deployment - kubernetes.core.k8s: - wait: true - definition: - apiVersion: apps/v1 - kind: Deployment - metadata: - name: '{{ SELF.application_name }}' - namespace: default - spec: - selector: - matchLabels: - app: '{{ SELF.application_name }}' - template: - metadata: - labels: - app: '{{ SELF.application_name }}' - spec: - containers: - - image: '{{ ".artifacts::docker_image::file" | eval }}' - name: '{{ SELF.application_name }}' - env: [] - ports: - - containerPort: '{{ SELF.application_port }}' - - name: create service - kubernetes.core.k8s: - definition: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.application_name }}' - namespace: default - spec: - ports: - - name: '{{ SELF.application_protocol }}' - port: '{{ SELF.application_port }}' - targetPort: '{{ SELF.application_port }}' - selector: - app: '{{ SELF.application_name }}' - type: ClusterIP - delete: - implementation: - primary: Ansible - operation_host: ORCHESTRATOR - environment: - K8S_AUTH_HOST: - eval: .::k8s_host - K8S_AUTH_SSL_CA_CERT: - eval: .::k8s_ca_cert_file - K8S_AUTH_CERT_FILE: - eval: .::k8s_client_cert_file - K8S_AUTH_KEY_FILE: - eval: .::k8s_client_key_file - inputs: - playbook: - q: - - name: delete service - kubernetes.core.k8s: - state: absent - api_version: v1 - kind: Service - namespace: default - name: '{{ SELF.application_name }}' - - name: delete deployment - kubernetes.core.k8s: - state: absent - api_version: app/v1 - kind: Deployment - namespace: default - name: '{{ SELF.application_name }}' - minio.server~service.application#docker.image::kubernetes@kubernetes.cluster: - derived_from: minio.server - metadata: - vintner_generated: 'true' - vintner_orchestrator: unfurl - attributes: - application_address: + get_input: gcp_region + gcp_project: type: string default: - eval: .::application_name + get_input: gcp_project interfaces: Standard: operations: @@ -11944,146 +20696,92 @@ node_types: inputs: playbook: q: - - name: touch manifest - register: manifest - ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.application.manifest.yaml' - - name: create manifest - ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: | - {{ deployment | to_yaml }} - --- - {{ service | to_yaml }} - vars: - deployment: - apiVersion: apps/v1 - kind: Deployment - metadata: - name: '{{ SELF.application_name }}' - namespace: default - spec: - selector: - matchLabels: - app: '{{ SELF.application_name }}' - template: - metadata: - labels: - app: '{{ SELF.application_name }}' - spec: - containers: - - image: '{{ ".artifacts::docker_image::file" | eval }}' - name: '{{ SELF.application_name }}' - env: [] - ports: - - containerPort: '{{ SELF.application_port }}' - service: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.application_name }}' - namespace: default - spec: - ports: - - name: '{{ SELF.application_protocol }}' - port: '{{ SELF.application_port }}' - targetPort: '{{ SELF.application_port }}' - selector: - app: '{{ SELF.application_name }}' - type: ClusterIP - - name: apply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} args: - executable: /usr/bin/bash - - name: wait for deployment - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} rollout status deployment/{{ SELF.application_name }} --timeout 60s + executable: /bin/bash + - name: enable GCP AppEngine + ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet args: - executable: /usr/bin/bash - delete: - implementation: - primary: Ansible - operation_host: ORCHESTRATOR - inputs: - playbook: - q: - - name: touch manifest - register: manifest + executable: /bin/bash + register: app_create_command + failed_when: + - "'Created' not in app_create_command.stderr" + - "'already contains' not in app_create_command.stderr" + - name: create working directory + register: directory ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.application.manifest.yaml' - - name: create manifest - ansible.builtin.copy: - dest: '{{ manifest.path }}' - content: | - {{ deployment | to_yaml }} - --- - {{ service | to_yaml }} - vars: - deployment: - apiVersion: apps/v1 - kind: Deployment - metadata: - name: '{{ SELF.application_name }}' - namespace: default - spec: - selector: - matchLabels: - app: '{{ SELF.application_name }}' - template: - metadata: - labels: - app: '{{ SELF.application_name }}' - spec: - containers: - - image: '{{ ".artifacts::docker_image::file" | eval }}' - name: '{{ SELF.application_name }}' - env: [] - ports: - - containerPort: '{{ SELF.application_port }}' - service: - apiVersion: v1 - kind: Service - metadata: - name: '{{ SELF.application_name }}' - namespace: default - spec: - ports: - - name: '{{ SELF.application_protocol }}' - port: '{{ SELF.application_port }}' - targetPort: '{{ SELF.application_port }}' - selector: - app: '{{ SELF.application_name }}' - type: ClusterIP - - name: unapply manifest - ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} + state: directory + - name: extract deployment artifact in working directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ directory.path }}' + - name: create specification + ansible.builtin.copy: + dest: '{{ directory.path }}/app.yaml' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + instance_class: F1 + env_variables: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + - name: create app + ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet args: - executable: /usr/bin/bash - minio.server~service.application#docker.image::terraform@kubernetes.cluster: + executable: /bin/bash + - name: browse app + register: browse_app + ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + args: + executable: /bin/bash + - name: set attributes + set_fact: + application_address: '{{ browse_app.stdout[8:] | trim }}' + application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' + resultTemplate: | + name: SELF + attributes: + application_address: '{{ outputs.application_address | trim }}' + application_endpoint: '{{ outputs.application_endpoint | trim }}' + outputs: + application_address: + application_endpoint: + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: activate service account + ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + args: + executable: /bin/bash + - name: delete app + ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + args: + executable: /bin/bash + minio.server~service.application#zip.archive::terraform@gcp.appengine: derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - k8s_host: - type: string - default: - get_input: k8s_host - k8s_ca_cert_file: - type: string - default: - get_input: k8s_ca_cert_file - k8s_client_cert_file: + gcp_service_account_file: type: string default: - get_input: k8s_client_cert_file - k8s_client_key_file: + get_input: gcp_service_account_file + gcp_region: type: string default: - get_input: k8s_client_key_file - attributes: - application_address: + get_input: gcp_region + gcp_project: type: string default: - eval: .::application_name + get_input: gcp_project interfaces: Standard: operations: @@ -12094,66 +20792,70 @@ node_types: implementation: primary: Terraform defaults: + outputs: + application_address: application_address + application_endpoint: application_endpoint inputs: main: terraform: - required_providers: - - kubernetes: - source: hashicorp/kubernetes - version: 2.31.0 - required_version: '>= 0.14.0' + - google: + source: hashicorp/google + version: 5.39.1 provider: - kubernetes: - - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} - client_key: ${file("{{ SELF.k8s_client_key_file }}")} - cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} - host: '{{ SELF.k8s_host }}' + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' + output: + application_address: + - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' + application_endpoint: + - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - kubernetes_deployment_v1: - application: - - metadata: - - name: '{{ SELF.application_name }}' - spec: - - selector: - - match_labels: - app: '{{ SELF.application_name }}' - template: - - metadata: - - labels: - app: '{{ SELF.application_name }}' - spec: - - container: - - env: [] - image: '{{ ".artifacts::docker_image::file" | eval }}' - name: '{{ SELF.application_name }}' - port: - - container_port: '{{ SELF.application_port }}' - kubernetes_service_v1: - application: - - metadata: - - name: '{{ SELF.application_name }}' - spec: - - port: - - name: '{{ SELF.application_protocol }}' - port: '{{ SELF.application_port }}' - target_port: '{{ SELF.application_port }}' - selector: - app: '{{ SELF.application_name }}' - type: ClusterIP - minio.server~service.application#tar.archive::ansible@*->remote.machine: + google_app_engine_standard_app_version: + app: + - delete_service_on_destroy: true + deployment: + - zip: + - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} + entrypoint: + - shell: '{{ SELF._management_start }}' + env_variables: + MINIO_ROOT_USER: '"{{ SELF.access_key }}"' + MINIO_ROOT_PASSWORD: '"{{ SELF.secret_key }}"' + runtime: '{{ SELF.application_language }}' + service: '{{ SELF.application_name }}' + service_account: ${google_service_account.custom_service_account.email} + version_id: v1 + google_project_iam_member: + gae_api: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/compute.networkUser + storage_viewer: + - member: serviceAccount:${google_service_account.custom_service_account.email} + project: ${google_service_account.custom_service_account.project} + role: roles/storage.objectViewer + google_service_account: + custom_service_account: + - account_id: '{{ SELF.application_name }}-account' + display_name: Custom Service Account + google_storage_bucket: + bucket: + - location: EU + name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' + google_storage_bucket_object: + object: + - bucket: ${google_storage_bucket.bucket.name} + name: object.zip + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + minio.server~software.application#apt.package::ansible@*->local.machine: derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -12168,39 +20870,44 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") - - name: extract deployment artifact from URL in application directory - ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -12209,50 +20916,21 @@ node_types: set -e {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - mode: '0755' - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/create.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: create service - ansible.builtin.copy: - dest: /etc/systemd/system/{{ SELF.application_name }}.service - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - - name: enable service - ansible.builtin.systemd: - name: '{{ SELF.application_name }}' - state: stopped - enabled: 'yes' - daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -12269,21 +20947,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -12298,27 +20968,23 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: start service - ansible.builtin.systemd: - name: '{{ SELF.application_name }}' - state: started - enabled: 'yes' - daemon_reload: 'yes' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -12332,237 +20998,217 @@ node_types: - name: call management operation ansible.builtin.shell: . .env && . .vintner/stop.sh args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: stop service - ansible.builtin.systemd: - name: '{{ SELF.application_name }}' - state: stopped - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - delete: - implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' - inputs: - playbook: - q: - - name: wait for ssh - wait_for_connection: - - name: copy management operation - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.vintner/delete.sh' - content: |- - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - mode: '0755' - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: call management operation - ansible.builtin.shell: . .env && . .vintner/delete.sh - args: - chdir: '{{ SELF.application_directory }}' - executable: /bin/bash - when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: delete systemd service - ansible.builtin.file: - path: /etc/systemd/system/{{ SELF.application_name }}.service - state: absent - - name: reload daemon - ansible.builtin.systemd: - daemon_reload: true - - name: delete application directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}' - state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - minio.server~service.application#tar.archive::terraform@*->remote.machine: - derived_from: minio.server - metadata: - vintner_generated: 'true' - properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address - application_directory: - type: string - default: - concat: - - /var/lib/ - - get_property: - - SELF - - application_name - interfaces: - Standard: - operations: - configure: - implementation: - primary: Terraform - delete: - implementation: - primary: Terraform - defaults: - inputs: - main: - resource: - terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' - provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-minio.server - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Reload systemd daemon - systemctl daemon-reload - - # Enable service - systemctl enable {{ SELF.application_name }} - destination: /tmp/create-minio.server.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-minio.server.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Start service - systemctl start {{ SELF.application_name }} - destination: /tmp/start-minio.server.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} - destination: /tmp/stop-minio.server.sh - - content: | - #!/usr/bin/bash - set -e + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + minio.server~software.application#apt.package::terraform@*->local.machine: + derived_from: minio.server + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - # Delete application directory - rm -rf "{{ SELF.application_directory }}" + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service + # Delete application directory + rm -rf "{{ SELF.application_directory }}" - # Reload system daemon - systemctl daemon-reload - destination: /tmp/delete-minio.server.sh - remote-exec: + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-minio.server.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: - inline: - sudo bash /tmp/create-minio.server.sh - sudo bash /tmp/configure-minio.server.sh @@ -12571,7 +21217,7 @@ node_types: - sudo bash /tmp/stop-minio.server.sh - sudo bash /tmp/delete-minio.server.sh when: destroy - minio.server~service.application#zip.archive::ansible@*->remote.machine: + minio.server~software.application#apt.package::ansible@*->remote.machine: derived_from: minio.server metadata: vintner_generated: 'true' @@ -12607,34 +21253,40 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: install operational dependencies + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache ansible.builtin.apt: - name: unzip update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: create vintner directory - ansible.builtin.file: - path: '{{ SELF.application_directory }}/.vintner' - state: directory - - name: create .env file - ansible.builtin.copy: - dest: '{{ SELF.application_directory }}/.env' - content: '' - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -12651,27 +21303,6 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: create service - ansible.builtin.copy: - dest: /etc/systemd/system/{{ SELF.application_name }}.service - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - - name: enable service - ansible.builtin.systemd: - name: '{{ SELF.application_name }}' - state: stopped - enabled: 'yes' - daemon_reload: 'yes' playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' @@ -12732,12 +21363,12 @@ node_types: {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} mode: '0755' when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: start service - ansible.builtin.systemd: - name: '{{ SELF.application_name }}' - state: started - enabled: 'yes' - daemon_reload: 'yes' + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' @@ -12753,6 +21384,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -12769,10 +21404,6 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: stop service - ansible.builtin.systemd: - name: '{{ SELF.application_name }}' - state: stopped playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' @@ -12804,22 +21435,19 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - - name: delete systemd service - ansible.builtin.file: - path: /etc/systemd/system/{{ SELF.application_name }}.service - state: absent - - name: reload daemon - ansible.builtin.systemd: - daemon_reload: true - name: delete application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - minio.server~service.application#zip.archive::terraform@*->remote.machine: + minio.server~software.application#apt.package::terraform@*->remote.machine: derived_from: minio.server metadata: vintner_generated: 'true' @@ -12866,50 +21494,61 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - destination: /tmp/artifact-minio.server - count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - [Unit] - After=network.target - - [Service] - Type=simple - ExecStart=/usr/bin/bash -c ". ./.vintner/start.sh" - WorkingDirectory={{ SELF.application_directory }} - EnvironmentFile={{ SELF.application_directory }}/.env - - [Install] - WantedBy=multi-user.target - destination: /etc/systemd/system/{{ SELF.application_name }}.service - content: | #!/usr/bin/bash set -e + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + # Create application directory mkdir -p {{ SELF.application_directory }} # Create application environment cat < {{ SELF.application_directory }}/.env - + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-minio.server {{ ".artifacts::zip_archive::file" | eval }} - fi - - # Extract deployment artifact - unzip /tmp/artifact-minio.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner - # Reload systemd daemon - systemctl daemon-reload + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e - # Enable service - systemctl enable {{ SELF.application_name }} + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh destination: /tmp/create-minio.server.sh - content: | #!/usr/bin/bash @@ -12933,25 +21572,24 @@ node_types: #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e - # Start service - systemctl start {{ SELF.application_name }} + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh destination: /tmp/start-minio.server.sh - content: | #!/usr/bin/bash set -e - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - # Copy operation cat < {{ SELF.application_directory }}/.vintner/stop.sh #!/usr/bin/bash @@ -12965,9 +21603,6 @@ node_types: cd {{ SELF.application_directory }} . .env . .vintner/stop.sh - - # Stop service - systemctl stop {{ SELF.application_name }} destination: /tmp/stop-minio.server.sh - content: | #!/usr/bin/bash @@ -12990,11 +21625,8 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - # Delete systemd service - rm -f /etc/systemd/system/{{ SELF.application_name }}.service - - # Reload system daemon - systemctl daemon-reload + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y destination: /tmp/delete-minio.server.sh remote-exec: - inline: @@ -13005,24 +21637,20 @@ node_types: - sudo bash /tmp/stop-minio.server.sh - sudo bash /tmp/delete-minio.server.sh when: destroy - minio.server~service.application#zip.archive::ansible@gcp.appengine: + minio.server~software.application#tar.archive::ansible@*->local.machine: derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -13033,57 +21661,138 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: enable GCP AppEngine - ansible.builtin.shell: gcloud app create --region {{ SELF.gcp_region }} --quiet + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - register: app_create_command - failed_when: - - "'Created' not in app_create_command.stderr" - - "'already contains' not in app_create_command.stderr" - - name: create working directory - register: directory - ansible.builtin.tempfile: - state: directory - - name: extract deployment artifact in working directory - ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - dest: '{{ directory.path }}' - - name: create specification + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation ansible.builtin.copy: - dest: '{{ directory.path }}/app.yaml' - content: '{{ manifest | to_yaml }}' - vars: - manifest: - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - instance_class: F1 - env_variables: {} - - name: create app - ansible.builtin.shell: gcloud app deploy {{ directory.path }} --quiet + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: browse app - register: browse_app - ansible.builtin.shell: 'gcloud app browse --service {{ SELF.application_name }} --no-launch-browser --quiet ' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - - name: set attributes - set_fact: - application_address: '{{ browse_app.stdout[8:] | trim }}' - application_endpoint: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ browse_app.stdout[8:] | trim }}:443' - resultTemplate: | - name: SELF - attributes: - application_address: '{{ outputs.application_address | trim }}' - application_endpoint: '{{ outputs.application_endpoint | trim }}' - outputs: - application_address: - application_endpoint: + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" delete: implementation: primary: Ansible @@ -13091,32 +21800,41 @@ node_types: inputs: playbook: q: - - name: activate service account - ansible.builtin.shell: gcloud auth activate-service-account --key-file {{ SELF.gcp_service_account_file }} --project {{ SELF.gcp_project }} - args: - executable: /bin/bash - - name: delete app - ansible.builtin.shell: gcloud app services delete {{ SELF.application_name }} --quiet + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh args: + chdir: '{{ SELF.application_directory }}' executable: /bin/bash - minio.server~service.application#zip.archive::terraform@gcp.appengine: + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + minio.server~software.application#tar.archive::terraform@*->local.machine: derived_from: minio.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -13127,63 +21845,164 @@ node_types: implementation: primary: Terraform defaults: - outputs: - application_address: application_address - application_endpoint: application_endpoint inputs: main: - terraform: - - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - output: - application_address: - - value: '{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com' - application_endpoint: - - value: '{{ SELF.application_protocol if SELF.application_protocol.endswith("s") else SELF.application_protocol + "s" }}://{{ SELF.application_name }}-dot-{{ SELF.gcp_project }}.ey.r.appspot.com:443' resource: - google_app_engine_standard_app_version: - app: - - delete_service_on_destroy: true - deployment: - - zip: - - source_url: https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name} - entrypoint: - - shell: '{{ SELF._management_start }}' - env_variables: {} - runtime: '{{ SELF.application_language }}' - service: '{{ SELF.application_name }}' - service_account: ${google_service_account.custom_service_account.email} - version_id: v1 - google_project_iam_member: - gae_api: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/compute.networkUser - storage_viewer: - - member: serviceAccount:${google_service_account.custom_service_account.email} - project: ${google_service_account.custom_service_account.project} - role: roles/storage.objectViewer - google_service_account: - custom_service_account: - - account_id: '{{ SELF.application_name }}-account' - display_name: Custom Service Account - google_storage_bucket: - bucket: - - location: EU - name: '{{ SELF.gcp_project }}-{{ SELF.application_name }}' - google_storage_bucket_object: - object: - - bucket: ${google_storage_bucket.bucket.name} - name: object.zip - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' - minio.server~software.application#apt.package::ansible@*->remote.machine: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-minio.server.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-minio.server.sh + - sudo bash /tmp/configure-minio.server.sh + - sudo bash /tmp/start-minio.server.sh + - inline: + - sudo bash /tmp/stop-minio.server.sh + - sudo bash /tmp/delete-minio.server.sh + when: destroy + minio.server~software.application#tar.archive::ansible@*->remote.machine: derived_from: minio.server metadata: vintner_generated: 'true' @@ -13219,40 +22038,33 @@ node_types: q: - name: wait for ssh wait_for_connection: - - name: run setup script - ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - args: - executable: /bin/bash - when: '".artifacts::apt_package::script" | eval != ""' - - name: add apt key - ansible.builtin.apt_key: - url: '{{ ".artifacts::apt_package::key" | eval }}' - keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - state: present - when: '".artifacts::apt_package::key" | eval != ""' - - name: add apt repository - ansible.builtin.apt_repository: - repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} - filename: '{{ ".artifacts::apt_package::repository" | eval }}' - state: present - when: '".artifacts::apt_package::source" | eval != ""' - - name: update apt cache - ansible.builtin.apt: - update_cache: 'yes' - - name: install dependencies - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' - state: present - when: '".artifacts::apt_package::dependencies" | eval != ""' - - name: install package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: present - environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -13315,6 +22127,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -13346,6 +22162,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -13397,15 +22217,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - - name: uninstall package - ansible.builtin.apt: - name: '{{ ".artifacts::apt_package::file" | eval }}' - state: absent playbookArgs: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - minio.server~software.application#apt.archive::terraform@*->remote.machine: + minio.server~software.application#tar.archive::terraform@*->remote.machine: derived_from: minio.server metadata: vintner_generated: 'true' @@ -13452,51 +22268,29 @@ node_types: user: '{{ SELF.os_ssh_user }}' provisioner: file: + - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + destination: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - content: | #!/usr/bin/bash set -e - # Run setup script - if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then - curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - - fi - - # Add apt key - if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then - curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg - fi - - # Add apt repository - if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then - echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} - fi - - # Update apt cache - apt-get update -y - - # Install dependencies - if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then - apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y - fi - - # Install package - {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y - # Create application directory mkdir -p {{ SELF.application_directory }} # Create application environment cat < {{ SELF.application_directory }}/.env - + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" EOF>> # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-minio.server {{ ".artifacts::apt_archive::file" | eval }} + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} fi # Extract deployment artifact - undefined + tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -13537,6 +22331,12 @@ node_types: #!/usr/bin/bash set -e + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + # Copy operation cat < {{ SELF.application_directory }}/.vintner/start.sh #!/usr/bin/bash @@ -13555,6 +22355,12 @@ node_types: #!/usr/bin/bash set -e + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + # Copy operation cat < {{ SELF.application_directory }}/.vintner/stop.sh #!/usr/bin/bash @@ -13589,9 +22395,6 @@ node_types: # Delete application directory rm -rf "{{ SELF.application_directory }}" - - # Uninstall package - apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y destination: /tmp/delete-minio.server.sh remote-exec: - inline: @@ -13602,20 +22405,12 @@ node_types: - sudo bash /tmp/stop-minio.server.sh - sudo bash /tmp/delete-minio.server.sh when: destroy - minio.server~software.application#tar.archive::ansible@*->remote.machine: + minio.server~software.application#zip.archive::ansible@*->local.machine: derived_from: minio.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file application_directory: type: string default: @@ -13630,31 +22425,31 @@ node_types: create: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' - name: create application directory ansible.builtin.file: path: '{{ SELF.application_directory }}' state: directory - name: extract deployment artifact in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::tar_archive::file" | eval).startswith("http") + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ ".artifacts::tar_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' remote_src: 'yes' - extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' - when: (".artifacts::tar_archive::file" | eval).startswith("http") + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -13662,7 +22457,9 @@ node_types: - name: create .env file ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' - content: '' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -13679,21 +22476,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' configure: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/configure.sh' @@ -13710,21 +22499,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' start: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "start" missing @@ -13745,21 +22526,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' stop: implementation: primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: assert management operation ansible.builtin.fail: dest: Management operation "stop" missing @@ -13780,21 +22553,13 @@ node_types: chdir: '{{ SELF.application_directory }}' executable: /bin/bash when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' delete: implementation: - primary: Ansible - operation_host: HOST - environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + primary: Ansible + operation_host: ORCHESTRATOR inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/delete.sh' @@ -13815,27 +22580,11 @@ node_types: ansible.builtin.file: path: '{{ SELF.application_directory }}' state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - minio.server~software.application#tar.archive::terraform@*->remote.machine: + minio.server~software.application#zip.archive::terraform@*->local.machine: derived_from: minio.server metadata: vintner_generated: 'true' properties: - os_ssh_user: - type: string - default: - get_input: os_ssh_user - os_ssh_key_file: - type: string - default: - get_input: os_ssh_key_file - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address application_directory: type: string default: @@ -13857,143 +22606,152 @@ node_types: inputs: main: resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-minio.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-minio.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-minio.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-minio.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-minio.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-minio.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-minio.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-minio.server.sh terraform_data: - vm: - - connection: - - host: '{{ SELF.os_ssh_host }}' - private_key: ${file("{{ SELF.os_ssh_key_file }}")} - type: ssh - user: '{{ SELF.os_ssh_user }}' + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete provisioner: - file: - - source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' - destination: /tmp/artifact-minio.server - count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' - - content: | - #!/usr/bin/bash - set -e - - # Create application directory - mkdir -p {{ SELF.application_directory }} - - # Create application environment - cat < {{ SELF.application_directory }}/.env - - EOF>> - - # Download deployment artifact if required - if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-minio.server {{ ".artifacts::tar_archive::file" | eval }} - fi - - # Extract deployment artifact - tar -xzf /tmp/artifact-minio.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} - - # Create vintner directory - mkdir -p {{ SELF.application_directory }}/.vintner - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/create.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/create.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/create.sh - destination: /tmp/create-minio.server.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/configure.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/configure.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/configure.sh - destination: /tmp/configure-minio.server.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "start" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/start.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/start.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/start.sh - destination: /tmp/start-minio.server.sh - - content: | - #!/usr/bin/bash - set -e - - # Assert operation - if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then - echo 'Management operation "stop" missing' - exit 1 - fi - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/stop.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/stop.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/stop.sh - destination: /tmp/stop-minio.server.sh - - content: | - #!/usr/bin/bash - set -e - - # Copy operation - cat < {{ SELF.application_directory }}/.vintner/delete.sh - #!/usr/bin/bash - set -e - - {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} - EOF>> - chmod +x {{ SELF.application_directory }}/.vintner/delete.sh - - # Execute operation - cd {{ SELF.application_directory }} - . .env - . .vintner/delete.sh - - # Delete application directory - rm -rf "{{ SELF.application_directory }}" - destination: /tmp/delete-minio.server.sh - remote-exec: + local-exec: - inline: - sudo bash /tmp/create-minio.server.sh - sudo bash /tmp/configure-minio.server.sh @@ -14052,12 +22810,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -14065,7 +22824,9 @@ node_types: - name: create .env file ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' - content: '' + content: |- + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/create.sh' @@ -14281,7 +23042,8 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - + MINIO_ROOT_USER="{{ SELF.access_key }}" + MINIO_ROOT_PASSWORD="{{ SELF.secret_key }}" EOF>> # Download deployment artifact if required @@ -14405,61 +23167,188 @@ node_types: - sudo bash /tmp/stop-minio.server.sh - sudo bash /tmp/delete-minio.server.sh when: destroy - redis.server~redis.server#cache.image::terraform@gcp.memorystore: + redis.server~redis.server#cache.image::ansible@docker.engine->local.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: start container + community.docker.docker_container: + name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: redis --port {{ SELF.application_port }} + env: + APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' + APPLICATION_NAME: '"{{ SELF.application_name }}"' + APPLICATION_PORT: '"{{ SELF.application_port }}"' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: stop container + community.docker.docker_container: + name: '{{ SELF.cache_name }}' + state: absent + redis.server~redis.server#cache.image::compose@docker.engine->local.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + attributes: + application_address: + type: string + default: 127.0.0.1 + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.cache_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.cache_name }}' + services: + application: + container_name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + environment: + APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' + APPLICATION_NAME: '"{{ SELF.application_name }}"' + APPLICATION_PORT: '"{{ SELF.application_port }}"' + - name: apply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + args: + executable: /usr/bin/bash + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: touch compose + register: compose + ansible.builtin.tempfile: + suffix: '{{ SELF.cache_name }}.compose.yaml' + - name: create compose + ansible.builtin.copy: + dest: '{{ compose.path }}' + content: '{{ manifest | to_yaml }}' + vars: + manifest: + name: '{{ SELF.cache_name }}' + services: + application: + container_name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + network_mode: host + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + environment: + APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' + APPLICATION_NAME: '"{{ SELF.application_name }}"' + APPLICATION_PORT: '"{{ SELF.application_port }}"' + - name: unapply compose + ansible.builtin.shell: docker compose -f {{ compose.path }} down + args: + executable: /usr/bin/bash + redis.server~redis.server#cache.image::terraform@docker.engine->local.machine: derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + attributes: + application_address: type: string - default: - get_input: gcp_project + default: 127.0.0.1 interfaces: Standard: operations: configure: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file delete: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file defaults: inputs: main: terraform: - required_providers: - - google: - source: hashicorp/google - version: 5.39.1 - mysql: - source: petoju/mysql - version: 3.0.48 + - docker: + source: kreuzwerker/docker + version: 3.0.2 provider: - google: - - credentials: '{{ SELF.gcp_service_account_file }}' - project: '{{ SELF.gcp_project }}' - region: '{{ SELF.gcp_region }}' - resource: {} - redis.server~redis.server#cache.image::ansible@docker.engine->local.machine: + docker: + - host: unix:///var/run/docker.sock + resource: + docker_container: + application: + - env: + - APPLICATION_PROTOCOL={{ SELF.application_protocol }} + - APPLICATION_NAME={{ SELF.application_name }} + - APPLICATION_PORT={{ SELF.application_port }} + image: ${docker_image.image.image_id} + name: '{{ SELF.cache_name }}' + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + network_mode: host + docker_image: + image: + - name: redis:{{ ".artifacts::cache_image::file" | eval }} + redis.server~redis.server#cache.image::ansible@docker.engine->remote.machine: derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file attributes: application_address: type: string @@ -14470,37 +23359,57 @@ node_types: create: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: + - name: wait for ssh + wait_for_connection: - name: start container community.docker.docker_container: - name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' + name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} network_mode: host + command: redis --port {{ SELF.application_port }} env: - CACHE_NAME: '"{{ SELF.cache_name }}"' - CACHE_PORT: '"{{ SELF.cache_port }}"' APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' APPLICATION_NAME: '"{{ SELF.application_name }}"' APPLICATION_PORT: '"{{ SELF.application_port }}"' + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' delete: implementation: primary: Ansible - operation_host: ORCHESTRATOR + operation_host: HOST + environment: + ANSIBLE_HOST_KEY_CHECKING: 'False' inputs: playbook: q: + - name: wait for ssh + wait_for_connection: - name: stop container community.docker.docker_container: - name: '{{ SELF.application_name }}' + name: '{{ SELF.cache_name }}' state: absent - redis.server~redis.server#cache.image::compose@docker.engine->local.machine: + playbookArgs: + - '--become' + - '--key-file={{ SELF.os_ssh_key_file }}' + - '--user={{ SELF.os_ssh_user }}' + redis.server~redis.server#cache.image::compose@docker.engine->remote.machine: derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl + properties: + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address attributes: application_address: type: string @@ -14518,22 +23427,24 @@ node_types: - name: touch compose register: compose ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.compose.yaml' + suffix: '{{ SELF.cache_name }}.compose.yaml' - name: create compose ansible.builtin.copy: dest: '{{ compose.path }}' content: '{{ manifest | to_yaml }}' vars: manifest: - name: '{{ SELF.application_name }}' + name: '{{ SELF.cache_name }}' services: application: - container_name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' + container_name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} network_mode: host + command: + - redis + - '--port' + - '{{ SELF.application_port }}' environment: - CACHE_NAME: '"{{ SELF.cache_name }}"' - CACHE_PORT: '"{{ SELF.cache_port }}"' APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' APPLICATION_NAME: '"{{ SELF.application_name }}"' APPLICATION_PORT: '"{{ SELF.application_port }}"' @@ -14541,6 +23452,8 @@ node_types: ansible.builtin.shell: docker compose -f {{ compose.path }} up -d args: executable: /usr/bin/bash + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' delete: implementation: primary: Ansible @@ -14551,22 +23464,24 @@ node_types: - name: touch compose register: compose ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.compose.yaml' + suffix: '{{ SELF.cache_name }}.compose.yaml' - name: create compose ansible.builtin.copy: dest: '{{ compose.path }}' content: '{{ manifest | to_yaml }}' vars: manifest: - name: '{{ SELF.application_name }}' + name: '{{ SELF.cache_name }}' services: application: - container_name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' + container_name: '{{ SELF.cache_name }}' + image: redis:{{ ".artifacts::cache_image::file" | eval }} network_mode: host + command: + - redis + - '--port' + - '{{ SELF.application_port }}' environment: - CACHE_NAME: '"{{ SELF.cache_name }}"' - CACHE_PORT: '"{{ SELF.cache_port }}"' APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' APPLICATION_NAME: '"{{ SELF.application_name }}"' APPLICATION_PORT: '"{{ SELF.application_port }}"' @@ -14574,11 +23489,26 @@ node_types: ansible.builtin.shell: docker compose -f {{ compose.path }} down args: executable: /usr/bin/bash - redis.server~redis.server#cache.image::terraform@docker.engine->local.machine: + environment: + DOCKER_HOST: '{{ SELF.os_ssh_host }}' + redis.server~redis.server#cache.image::terraform@docker.engine->remote.machine: derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl + properties: + os_ssh_user: + type: string + default: + get_input: os_ssh_user + os_ssh_key_file: + type: string + default: + get_input: os_ssh_key_file + os_ssh_host: + type: string + default: + eval: .::.requirements::[.name=host]::.target::management_address attributes: application_address: type: string @@ -14602,102 +23532,292 @@ node_types: version: 3.0.2 provider: docker: - - host: unix:///var/run/docker.sock + - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 + ssh_opts: + - '-i' + - '{{ SELF.os_ssh_key_file }}' + - '-o' + - IdentitiesOnly=yes + - '-o' + - BatchMode=yes + - '-o' + - UserKnownHostsFile=/dev/null + - '-o' + - StrictHostKeyChecking=no + resource: + docker_container: + application: + - env: + - APPLICATION_PROTOCOL={{ SELF.application_protocol }} + - APPLICATION_NAME={{ SELF.application_name }} + - APPLICATION_PORT={{ SELF.application_port }} + image: ${docker_image.image.image_id} + name: '{{ SELF.cache_name }}' + command: + - redis + - '--port' + - '{{ SELF.application_port }}' + network_mode: host + docker_image: + image: + - name: redis:{{ ".artifacts::cache_image::file" | eval }} + redis.server~redis.server#cache.image::ansible@gcp.memorystore: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: create redis + google.cloud.gcp_redis_instance: + name: '{{ SELF.cache_name }}' + memory_size_gb: 1 + region: '{{ SELF.gcp_region }}' + project: '{{ SELF.gcp_project }}' + register: redis_info + - name: set attributes + set_fact: + application_endpoint: '{{ redis_info.host }}:{{ redis_info.port }}' + application_address: '{{ redis_info.host }}' + application_port: '{{ redis_info.port }}' + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + environment: + GCP_SERVICE_ACCOUNT_FILE: + eval: .::gcp_service_account_file + GCP_AUTH_KIND: serviceaccount + inputs: + playbook: + q: + - name: delete redis + google.cloud.gcp_redis_instance: + name: '{{ SELF.cache_name }}' + project: '{{ SELF.gcp_project }}' + state: absent + redis.server~redis.server#cache.image::terraform@gcp.memorystore: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + gcp_service_account_file: + type: string + default: + get_input: gcp_service_account_file + gcp_region: + type: string + default: + get_input: gcp_region + gcp_project: + type: string + default: + get_input: gcp_project + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + environment: + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file + delete: + implementation: + primary: Terraform + environment: + GOOGLE_APPLICATION_CREDENTIALS: + eval: .::gcp_service_account_file + defaults: + inputs: + main: + terraform: + - required_providers: + - google: + source: hashicorp/google + version: 5.39.1 + provider: + google: + - credentials: '{{ SELF.gcp_service_account_file }}' + project: '{{ SELF.gcp_project }}' + region: '{{ SELF.gcp_region }}' resource: - docker_container: - application: - - env: - - CACHE_NAME={{ SELF.cache_name }} - - CACHE_PORT={{ SELF.cache_port }} - - APPLICATION_PROTOCOL={{ SELF.application_protocol }} - - APPLICATION_NAME={{ SELF.application_name }} - - APPLICATION_PORT={{ SELF.application_port }} - image: ${docker_image.image.image_id} - name: '{{ SELF.application_name }}' - network_mode: host - docker_image: - image: - - name: '{{ ".artifacts::docker_image::file" | eval }}' - redis.server~redis.server#cache.image::ansible@docker.engine->remote.machine: + google_redis_instance: + cache: + - name: '{{ SELF.cache_name }}' + memory_size_gb: 1 + lifecycle: + prevent_destroy: true + output: + application_endpoint: + - value: ${google_redis_instance.cache.host}:${google_redis_instance.cache.port} + application_address: + - value: ${google_redis_instance.cache.host} + application_port: + - value: ${google_redis_instance.cache.port} + outputs: + application_endpoint: application_endpoint + application_address: application_address + application_port: application_port + redis.server~redis.server#cache.image::ansible@kubernetes.cluster: derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + k8s_host: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: os_ssh_key_file + get_input: k8s_ca_cert_file + k8s_client_cert_file: + type: string + default: + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file attributes: application_address: type: string - default: 127.0.0.1 + default: + eval: .::cache_name interfaces: Standard: operations: create: implementation: primary: Ansible - operation_host: HOST + operation_host: ORCHESTRATOR environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: start container - community.docker.docker_container: - name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' - network_mode: host - env: - CACHE_NAME: '"{{ SELF.cache_name }}"' - CACHE_PORT: '"{{ SELF.cache_port }}"' - APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' - APPLICATION_NAME: '"{{ SELF.application_name }}"' - APPLICATION_PORT: '"{{ SELF.application_port }}"' - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' + - name: create deployment + kubernetes.core.k8s: + wait: true + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.application_name }}' + template: + metadata: + labels: + app: '{{ SELF.application_name }}' + spec: + containers: + - image: redis:{{ ".artifacts::cache_image::file" | eval }} + name: '{{ SELF.application_name }}' + env: + - name: APPLICATION_PROTOCOL + value: '"{{ SELF.application_protocol }}"' + - name: APPLICATION_NAME + value: '"{{ SELF.application_name }}"' + - name: APPLICATION_PORT + value: '"{{ SELF.application_port }}"' + command: redis --port {{ SELF.application_port }} + ports: + - containerPort: '{{ SELF.application_port }}' + - name: create service + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.application_name }}' + namespace: default + spec: + ports: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + targetPort: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP delete: implementation: primary: Ansible - operation_host: HOST + operation_host: ORCHESTRATOR environment: - ANSIBLE_HOST_KEY_CHECKING: 'False' + K8S_AUTH_HOST: + eval: .::k8s_host + K8S_AUTH_SSL_CA_CERT: + eval: .::k8s_ca_cert_file + K8S_AUTH_CERT_FILE: + eval: .::k8s_client_cert_file + K8S_AUTH_KEY_FILE: + eval: .::k8s_client_key_file inputs: playbook: q: - - name: wait for ssh - wait_for_connection: - - name: stop container - community.docker.docker_container: + - name: delete service + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: Service + namespace: default name: '{{ SELF.application_name }}' + - name: delete deployment + kubernetes.core.k8s: state: absent - playbookArgs: - - '--become' - - '--key-file={{ SELF.os_ssh_key_file }}' - - '--user={{ SELF.os_ssh_user }}' - redis.server~redis.server#cache.image::compose@docker.engine->remote.machine: + api_version: app/v1 + kind: Deployment + namespace: default + name: '{{ SELF.application_name }}' + redis.server~redis.server#cache.image::kubernetes@kubernetes.cluster: derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl - properties: - os_ssh_host: - type: string - default: - eval: .::.requirements::[.name=host]::.target::management_address attributes: application_address: type: string - default: 127.0.0.1 + default: + eval: .::cache_name interfaces: Standard: operations: @@ -14708,34 +23828,68 @@ node_types: inputs: playbook: q: - - name: touch compose - register: compose + - name: touch manifest + register: manifest ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.compose.yaml' - - name: create compose + suffix: '{{ SELF.application_name }}.application.manifest.yaml' + - name: create manifest ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} vars: - manifest: - name: '{{ SELF.application_name }}' - services: - application: - container_name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' - network_mode: host - environment: - CACHE_NAME: '"{{ SELF.cache_name }}"' - CACHE_PORT: '"{{ SELF.cache_port }}"' - APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' - APPLICATION_NAME: '"{{ SELF.application_name }}"' - APPLICATION_PORT: '"{{ SELF.application_port }}"' - - name: apply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} up -d + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.cache_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.cache_name }}' + template: + metadata: + labels: + app: '{{ SELF.cache_name }}' + spec: + containers: + - image: redis:{{ ".artifacts::cache_image::file" | eval }} + name: '{{ SELF.cache_name }}' + env: + - name: APPLICATION_PROTOCOL + value: '"{{ SELF.application_protocol }}"' + - name: APPLICATION_NAME + value: '"{{ SELF.application_name }}"' + - name: APPLICATION_PORT + value: '"{{ SELF.application_port }}"' + command: redis --port {{ SELF.application_port }} + ports: + - containerPort: '{{ SELF.cache_port }}' + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.cache_name }}' + namespace: default + spec: + ports: + - name: redis + port: '{{ SELF.cache_port }}' + targetPort: '{{ SELF.cache_port }}' + selector: + app: '{{ SELF.cache_name }}' + type: ClusterIP + - name: apply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} apply -f {{ manifest.path }} + args: + executable: /usr/bin/bash + - name: wait for deployment + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} rollout status deployment/{{ SELF.application_name }} --timeout 60s args: executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' delete: implementation: primary: Ansible @@ -14743,56 +23897,91 @@ node_types: inputs: playbook: q: - - name: touch compose - register: compose + - name: touch manifest + register: manifest ansible.builtin.tempfile: - suffix: '{{ SELF.application_name }}.compose.yaml' - - name: create compose + suffix: '{{ SELF.application_name }}.application.manifest.yaml' + - name: create manifest ansible.builtin.copy: - dest: '{{ compose.path }}' - content: '{{ manifest | to_yaml }}' + dest: '{{ manifest.path }}' + content: | + {{ deployment | to_yaml }} + --- + {{ service | to_yaml }} vars: - manifest: - name: '{{ SELF.application_name }}' - services: - application: - container_name: '{{ SELF.application_name }}' - image: '{{ ".artifacts::docker_image::file" | eval }}' - network_mode: host - environment: - CACHE_NAME: '"{{ SELF.cache_name }}"' - CACHE_PORT: '"{{ SELF.cache_port }}"' - APPLICATION_PROTOCOL: '"{{ SELF.application_protocol }}"' - APPLICATION_NAME: '"{{ SELF.application_name }}"' - APPLICATION_PORT: '"{{ SELF.application_port }}"' - - name: unapply compose - ansible.builtin.shell: docker compose -f {{ compose.path }} down + deployment: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: '{{ SELF.cache_name }}' + namespace: default + spec: + selector: + matchLabels: + app: '{{ SELF.cache_name }}' + template: + metadata: + labels: + app: '{{ SELF.cache_name }}' + spec: + containers: + - image: redis:{{ ".artifacts::cache_image::file" | eval }} + name: '{{ SELF.cache_name }}' + env: + - name: APPLICATION_PROTOCOL + value: '"{{ SELF.application_protocol }}"' + - name: APPLICATION_NAME + value: '"{{ SELF.application_name }}"' + - name: APPLICATION_PORT + value: '"{{ SELF.application_port }}"' + command: redis --port {{ SELF.application_port }} + ports: + - containerPort: '{{ SELF.cache_port }}' + service: + apiVersion: v1 + kind: Service + metadata: + name: '{{ SELF.cache_name }}' + namespace: default + spec: + ports: + - name: redis + port: '{{ SELF.cache_port }}' + targetPort: '{{ SELF.cache_port }}' + selector: + app: '{{ SELF.cache_name }}' + type: ClusterIP + - name: unapply manifest + ansible.builtin.shell: kubectl --server {{ SELF.k8s_host }} --certificate-authority {{ SELF.k8s_ca_cert_file }} --client-certificate {{ SELF.k8s_client_cert_file }} --client-key {{ SELF.k8s_client_key_file }} delete -f {{ manifest.path }} args: executable: /usr/bin/bash - environment: - DOCKER_HOST: '{{ SELF.os_ssh_host }}' - redis.server~redis.server#cache.image::terraform@docker.engine->remote.machine: + redis.server~redis.server#cache.image::terraform@kubernetes.cluster: derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - os_ssh_user: + k8s_host: type: string default: - get_input: os_ssh_user - os_ssh_key_file: + get_input: k8s_host + k8s_ca_cert_file: type: string default: - get_input: os_ssh_key_file - os_ssh_host: + get_input: k8s_ca_cert_file + k8s_client_cert_file: type: string default: - eval: .::.requirements::[.name=host]::.target::management_address + get_input: k8s_client_cert_file + k8s_client_key_file: + type: string + default: + get_input: k8s_client_key_file attributes: application_address: type: string - default: 127.0.0.1 + default: + eval: .::application_name interfaces: Standard: operations: @@ -14807,56 +23996,69 @@ node_types: main: terraform: - required_providers: - - docker: - source: kreuzwerker/docker - version: 3.0.2 + - kubernetes: + source: hashicorp/kubernetes + version: 2.31.0 + required_version: '>= 0.14.0' provider: - docker: - - host: ssh://{{ SELF.os_ssh_user }}@{{ SELF.os_ssh_host }}:22 - ssh_opts: - - '-i' - - '{{ SELF.os_ssh_key_file }}' - - '-o' - - IdentitiesOnly=yes - - '-o' - - BatchMode=yes - - '-o' - - UserKnownHostsFile=/dev/null - - '-o' - - StrictHostKeyChecking=no + kubernetes: + - client_certificate: ${file("{{ SELF.k8s_client_cert_file }}")} + client_key: ${file("{{ SELF.k8s_client_key_file }}")} + cluster_ca_certificate: ${file("{{ SELF.k8s_ca_cert_file }}")} + host: '{{ SELF.k8s_host }}' resource: - docker_container: + kubernetes_deployment_v1: application: - - env: - - CACHE_NAME={{ SELF.cache_name }} - - CACHE_PORT={{ SELF.cache_port }} - - APPLICATION_PROTOCOL={{ SELF.application_protocol }} - - APPLICATION_NAME={{ SELF.application_name }} - - APPLICATION_PORT={{ SELF.application_port }} - image: ${docker_image.image.image_id} - name: '{{ SELF.application_name }}' - network_mode: host - docker_image: - image: - - name: '{{ ".artifacts::docker_image::file" | eval }}' - redis.server~redis.server#cache.image::ansible@kubernetes.cluster: + - metadata: + - name: '{{ SELF.application_name }}' + spec: + - selector: + - match_labels: + app: '{{ SELF.application_name }}' + template: + - metadata: + - labels: + app: '{{ SELF.application_name }}' + spec: + - container: + - env: + - name: APPLICATION_PROTOCOL + value: '"{{ SELF.application_protocol }}"' + - name: APPLICATION_NAME + value: '"{{ SELF.application_name }}"' + - name: APPLICATION_PORT + value: '"{{ SELF.application_port }}"' + image: redis:{{ ".artifacts::cache_image::file" | eval }} + name: '{{ SELF.application_name }}' + command: redis --port {{ SELF.application_port }} + port: + - container_port: '{{ SELF.application_port }}' + kubernetes_service_v1: + application: + - metadata: + - name: '{{ SELF.application_name }}' + spec: + - port: + - name: '{{ SELF.application_protocol }}' + port: '{{ SELF.application_port }}' + target_port: '{{ SELF.application_port }}' + selector: + app: '{{ SELF.application_name }}' + type: ClusterIP + redis.server~software.application#apt.package::ansible@*->local.machine: derived_from: redis.server metadata: vintner_generated: 'true' vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: @@ -14866,53 +24068,351 @@ node_types: operation_host: ORCHESTRATOR inputs: playbook: - q: [] + q: + - name: run setup script + ansible.builtin.shell: curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + args: + executable: /bin/bash + when: '".artifacts::apt_package::script" | eval != ""' + - name: add apt key + ansible.builtin.apt_key: + url: '{{ ".artifacts::apt_package::key" | eval }}' + keyring: /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + state: present + when: '".artifacts::apt_package::key" | eval != ""' + - name: add apt repository + ansible.builtin.apt_repository: + repo: deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }} + filename: '{{ ".artifacts::apt_package::repository" | eval }}' + state: present + when: '".artifacts::apt_package::source" | eval != ""' + - name: update apt cache + ansible.builtin.apt: + update_cache: 'yes' + - name: install dependencies + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }}' + state: present + when: '".artifacts::apt_package::dependencies" | eval != ""' + - name: install package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: present + environment: '{{ ".artifacts::apt_package::env" | eval | split | map("split", "=") | community.general.dict }}' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" delete: implementation: primary: Ansible operation_host: ORCHESTRATOR inputs: playbook: - q: [] - redis.server~redis.server#cache.image::terraform@kubernetes.cluster: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + - name: uninstall package + ansible.builtin.apt: + name: '{{ ".artifacts::apt_package::file" | eval }}' + state: absent + redis.server~software.application#apt.package::terraform@*->local.machine: derived_from: redis.server metadata: vintner_generated: 'true' - vintner_orchestrator: unfurl properties: - gcp_service_account_file: - type: string - default: - get_input: gcp_service_account_file - gcp_region: - type: string - default: - get_input: gcp_region - gcp_project: + application_directory: type: string default: - get_input: gcp_project + concat: + - /var/lib/ + - get_property: + - SELF + - application_name interfaces: Standard: operations: configure: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file delete: implementation: primary: Terraform - environment: - GOOGLE_APPLICATION_CREDENTIALS: - eval: .::gcp_service_account_file defaults: inputs: main: - terraform: [] - provider: {} - resource: {} + resource: + local_file: + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Run setup script + if [[ "{{ ".artifacts::apt_package::script" | eval }}" != "" ]]; then + curl -fsSL {{ ".artifacts::apt_package::script" | eval }} | sudo -E bash - + fi + + # Add apt key + if [[ "{{ ".artifacts::apt_package::key" | eval }}" != "" ]]; then + curl -1sLf {{ ".artifacts::apt_package::key" | eval }} | gpg --dearmor --yes -o /usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg + fi + + # Add apt repository + if [[ "{{ ".artifacts::apt_package::source" | eval }}" != "" ]]; then + echo "deb [signed-by=/usr/share/keyrings/{{ ".artifacts::apt_package::repository" | eval }}.gpg] {{ ".artifacts::apt_package::source" | eval }}" | tee {{ ".artifacts::apt_package::repository" | eval }} + fi + + # Update apt cache + apt-get update -y + + # Install dependencies + if [[ "{{ ".artifacts::apt_package::dependencies" | eval }}" != "" ]]; then + apt-get install {{ ".artifacts::apt_package::dependencies" | eval | split(",") | map("trim") }} -y + fi + + # Install package + {{ ".artifacts::apt_package::env" | eval }} apt-get install {{ ".artifacts::apt_package::file" | eval }} -y + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + EOF>> + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-redis.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-redis.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-redis.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-redis.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + + # Uninstall package + apt-get uninstall {{ ".artifacts::apt_package::file" | eval }} -y + filename: /tmp/delete-redis.server.sh + terraform_data: + local: + - provisioner: + depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + local-exec: + - inline: + - sudo bash /tmp/create-redis.server.sh + - sudo bash /tmp/configure-redis.server.sh + - sudo bash /tmp/start-redis.server.sh + - inline: + - sudo bash /tmp/stop-redis.server.sh + - sudo bash /tmp/delete-redis.server.sh + when: destroy redis.server~software.application#apt.package::ansible@*->remote.machine: derived_from: redis.server metadata: @@ -15045,6 +24545,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/start.sh' @@ -15076,6 +24580,10 @@ node_types: q: - name: wait for ssh wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" - name: copy management operation ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.vintner/stop.sh' @@ -15135,7 +24643,7 @@ node_types: - '--become' - '--key-file={{ SELF.os_ssh_key_file }}' - '--user={{ SELF.os_ssh_user }}' - redis.server~software.application#apt.archive::terraform@*->remote.machine: + redis.server~software.application#apt.package::terraform@*->remote.machine: derived_from: redis.server metadata: vintner_generated: 'true' @@ -15217,21 +24725,11 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - CACHE_NAME="{{ SELF.cache_name }}" - CACHE_PORT="{{ SELF.cache_port }}" APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" APPLICATION_NAME="{{ SELF.application_name }}" APPLICATION_PORT="{{ SELF.application_port }}" EOF>> - # Download deployment artifact if required - if [[ "{{ ".artifacts::apt_archive::file" | eval }}" == http* ]]; then - wget -O /tmp/artifact-redis.server {{ ".artifacts::apt_archive::file" | eval }} - fi - - # Extract deployment artifact - undefined - # Create vintner directory mkdir -p {{ SELF.application_directory }}/.vintner @@ -15336,6 +24834,373 @@ node_types: - sudo bash /tmp/stop-redis.server.sh - sudo bash /tmp/delete-redis.server.sh when: destroy + redis.server~software.application#tar.archive::ansible@*->local.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::tar_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::tar_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::tar_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::tar_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: wait for ssh + wait_for_connection: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + redis.server~software.application#tar.archive::terraform@*->local.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::tar_archive::file" | eval }}' + filename: /tmp/artifact-redis.server + count: '{{ (not (".artifacts::tar_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::tar_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-redis.server {{ ".artifacts::tar_archive::file" | eval }} + fi + + # Extract deployment artifact + tar -xzf /tmp/artifact-redis.server -C {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-redis.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-redis.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-redis.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-redis.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-redis.server.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-redis.server.sh + - sudo bash /tmp/configure-redis.server.sh + - sudo bash /tmp/start-redis.server.sh + - inline: + - sudo bash /tmp/stop-redis.server.sh + - sudo bash /tmp/delete-redis.server.sh + when: destroy redis.server~software.application#tar.archive::ansible@*->remote.machine: derived_from: redis.server metadata: @@ -15397,8 +25262,6 @@ node_types: ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' content: |- - CACHE_NAME="{{ SELF.cache_name }}" - CACHE_PORT="{{ SELF.cache_port }}" APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" APPLICATION_NAME="{{ SELF.application_name }}" APPLICATION_PORT="{{ SELF.application_port }}" @@ -15617,8 +25480,6 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - CACHE_NAME="{{ SELF.cache_name }}" - CACHE_PORT="{{ SELF.cache_port }}" APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" APPLICATION_NAME="{{ SELF.application_name }}" APPLICATION_PORT="{{ SELF.application_port }}" @@ -15745,6 +25606,363 @@ node_types: - sudo bash /tmp/stop-redis.server.sh - sudo bash /tmp/delete-redis.server.sh when: destroy + redis.server~software.application#zip.archive::ansible@*->local.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + vintner_orchestrator: unfurl + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + create: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: install operational dependencies + ansible.builtin.apt: + name: unzip + update_cache: 'yes' + - name: create application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: directory + - name: extract deployment artifact in application directory + ansible.builtin.unarchive: + src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: not (".artifacts::zip_archive::file" | eval).startswith("http") + - name: extract deployment artifact from URL in application directory + ansible.builtin.unarchive: + src: '{{ ".artifacts::zip_archive::file" | eval }}' + dest: '{{ SELF.application_directory }}' + remote_src: 'yes' + extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' + when: (".artifacts::zip_archive::file" | eval).startswith("http") + - name: create vintner directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}/.vintner' + state: directory + - name: create .env file + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.env' + content: |- + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/create.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + mode: '0755' + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/create.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_create != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + configure: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/configure.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + mode: '0755' + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/configure.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_configure != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + start: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "start" missing + when: SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/start.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + mode: '0755' + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/start.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_start != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + stop: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: assert management operation + ansible.builtin.fail: + dest: Management operation "stop" missing + when: SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/stop.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + mode: '0755' + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/stop.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_stop != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + delete: + implementation: + primary: Ansible + operation_host: ORCHESTRATOR + inputs: + playbook: + q: + - name: copy management operation + ansible.builtin.copy: + dest: '{{ SELF.application_directory }}/.vintner/delete.sh' + content: |- + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + mode: '0755' + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: call management operation + ansible.builtin.shell: . .env && . .vintner/delete.sh + args: + chdir: '{{ SELF.application_directory }}' + executable: /bin/bash + when: SELF._management_delete != "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" + - name: delete application directory + ansible.builtin.file: + path: '{{ SELF.application_directory }}' + state: absent + redis.server~software.application#zip.archive::terraform@*->local.machine: + derived_from: redis.server + metadata: + vintner_generated: 'true' + properties: + application_directory: + type: string + default: + concat: + - /var/lib/ + - get_property: + - SELF + - application_name + interfaces: + Standard: + operations: + configure: + implementation: + primary: Terraform + delete: + implementation: + primary: Terraform + defaults: + inputs: + main: + resource: + local_file: + tmp_artifact: + source: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + filename: /tmp/artifact-redis.server + count: '{{ (not (".artifacts::zip_archive::file" | eval).startswith("http")) | ternary(1, 0) }}' + tmp_create: + content: | + #!/usr/bin/bash + set -e + + # Create application directory + mkdir -p {{ SELF.application_directory }} + + # Create application environment + cat < {{ SELF.application_directory }}/.env + APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" + APPLICATION_NAME="{{ SELF.application_name }}" + APPLICATION_PORT="{{ SELF.application_port }}" + EOF>> + + # Download deployment artifact if required + if [[ "{{ ".artifacts::zip_archive::file" | eval }}" == http* ]]; then + wget -O /tmp/artifact-redis.server {{ ".artifacts::zip_archive::file" | eval }} + fi + + # Extract deployment artifact + unzip /tmp/artifact-redis.server -d {{ SELF.application_directory }} {{ ".artifacts::tar_archive::extra_opts" | eval | map_value }} + + # Create vintner directory + mkdir -p {{ SELF.application_directory }}/.vintner + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/create.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_create == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_create) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/create.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/create.sh + filename: /tmp/create-redis.server.sh + tmp_configure: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/configure.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_configure == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_configure) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/configure.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/configure.sh + filename: /tmp/configure-redis.server.sh + tmp_start: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_start | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "start" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/start.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_start == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_start) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/start.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/start.sh + filename: /tmp/start-redis.server.sh + tmp_stop: + content: | + #!/usr/bin/bash + set -e + + # Assert operation + if [[ "{{ SELF._management_stop | split('\n') | first }}" == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ]]; then + echo 'Management operation "stop" missing' + exit 1 + fi + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/stop.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_stop == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_stop) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/stop.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/stop.sh + filename: /tmp/stop-redis.server.sh + tmp_delete: + content: | + #!/usr/bin/bash + set -e + + # Copy operation + cat < {{ SELF.application_directory }}/.vintner/delete.sh + #!/usr/bin/bash + set -e + + {{ (SELF._management_delete == "VINTNER_MANAGEMENT_OPERATION_UNDEFINED" ) | ternary("echo 0", SELF._management_delete) }} + EOF>> + chmod +x {{ SELF.application_directory }}/.vintner/delete.sh + + # Execute operation + cd {{ SELF.application_directory }} + . .env + . .vintner/delete.sh + + # Delete application directory + rm -rf "{{ SELF.application_directory }}" + filename: /tmp/delete-redis.server.sh + terraform_data: + local: + - depends_on: + - local_file.tmp_artifact + - local_file.tmp_create + - local_file.tmp_configure + - local_file.tmp_start + - local_file.tmp_stop + - local_file.tmp_delete + provisioner: + local-exec: + - inline: + - sudo bash /tmp/create-redis.server.sh + - sudo bash /tmp/configure-redis.server.sh + - sudo bash /tmp/start-redis.server.sh + - inline: + - sudo bash /tmp/stop-redis.server.sh + - sudo bash /tmp/delete-redis.server.sh + when: destroy redis.server~software.application#zip.archive::ansible@*->remote.machine: derived_from: redis.server metadata: @@ -15795,12 +26013,13 @@ node_types: dest: '{{ SELF.application_directory }}' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' when: not (".artifacts::zip_archive::file" | eval).startswith("http") - - name: extract deployment artifact in application directory + - name: extract deployment artifact from URL in application directory ansible.builtin.unarchive: - src: '{{ "project" | get_dir }}/ensemble/{{ ".artifacts::zip_archive::file" | eval }}' + src: '{{ ".artifacts::zip_archive::file" | eval }}' dest: '{{ SELF.application_directory }}' + remote_src: 'yes' extra_opts: '{{ ".artifacts::zip_archive::extra_opts" | eval | map_value }}' - when: not (".artifacts::zip_archive::file" | eval).startswith("http") + when: (".artifacts::zip_archive::file" | eval).startswith("http") - name: create vintner directory ansible.builtin.file: path: '{{ SELF.application_directory }}/.vintner' @@ -15809,8 +26028,6 @@ node_types: ansible.builtin.copy: dest: '{{ SELF.application_directory }}/.env' content: |- - CACHE_NAME="{{ SELF.cache_name }}" - CACHE_PORT="{{ SELF.cache_port }}" APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" APPLICATION_NAME="{{ SELF.application_name }}" APPLICATION_PORT="{{ SELF.application_port }}" @@ -16029,8 +26246,6 @@ node_types: # Create application environment cat < {{ SELF.application_directory }}/.env - CACHE_NAME="{{ SELF.cache_name }}" - CACHE_PORT="{{ SELF.cache_port }}" APPLICATION_PROTOCOL="{{ SELF.application_protocol }}" APPLICATION_NAME="{{ SELF.application_name }}" APPLICATION_PORT="{{ SELF.application_port }}" diff --git a/examples/unfurl-technology---shop---plus-maintenance-automated/scripts/quality.sh b/examples/unfurl-technology---shop---plus-maintenance-automated/scripts/quality.sh index f6ec287d7c..fb4b90537a 100755 --- a/examples/unfurl-technology---shop---plus-maintenance-automated/scripts/quality.sh +++ b/examples/unfurl-technology---shop---plus-maintenance-automated/scripts/quality.sh @@ -5,4 +5,9 @@ set -e source configuration.sh # Quality -$VINTNER template quality --template ${TEMPLATE_DIR}/variable-service-template.yaml --presets ${DEPLOYMENT_VARIANT} \ No newline at end of file +for dir in ../tests/*/; +#for dir in "../tests/gcp"; +do + dir=$(basename $dir) + echo "${dir}: $($VINTNER template quality --template ${TEMPLATE_DIR}/variable-service-template.yaml --inputs ${TEMPLATE_DIR}/tests/${dir}/inputs.yaml)" +done diff --git a/src/controller/study/technology.ts b/src/controller/study/technology.ts index e869eef50a..1d065436b0 100644 --- a/src/controller/study/technology.ts +++ b/src/controller/study/technology.ts @@ -4,6 +4,7 @@ import * as files from '#files' import Graph from '#graph/graph' import Loader from '#graph/loader' import * as utils from '#utils' +import * as console from 'node:console' import path from 'path' export type StudyTechnologyOptions = { @@ -240,12 +241,21 @@ export default async function (options: StudyTechnologyOptions) { qualityData.push({ scenario: original, - expert: quality.max_weight.weight, - non_expert: [quality.min_weight, quality.max_weight], - random: [quality.min_weight.weight, quality.max_weight.weight], - counting: [quality.min_count.min.weight, quality.min_count.max.weight], - quality: quality.max_weight.weight, - quality_counting: quality.max_weight_min_count.weight, + expert: utils.roundNumber(quality.max_weight.technologies.weight_average), + non_expert: [ + utils.roundNumber(quality.min_weight.technologies.weight_average), + utils.roundNumber(quality.max_weight.technologies.weight_average), + ], + random: [ + utils.roundNumber(quality.min_weight.technologies.weight_average), + utils.roundNumber(quality.max_weight.technologies.weight_average), + ], + counting: [ + utils.roundNumber(quality.min_count.min.technologies.weight_average), + utils.roundNumber(quality.min_count.max.technologies.weight_average), + ], + quality: utils.roundNumber(quality.max_weight.technologies.weight_average), + quality_counting: utils.roundNumber(quality.max_weight_min_count.technologies.weight_average), }) } @@ -341,6 +351,10 @@ export default async function (options: StudyTechnologyOptions) { */ relativeMaintenanceDiff(vdmm_plus_automated_diff, vdmm_baseline_diff), ]) + + console.log() + console.log('CAUTION: Is this case study running with the latest implementation?') + console.log() } type StudyConfig = { diff --git a/src/controller/template/quality.ts b/src/controller/template/quality.ts index 3745c46835..91ccfee9fb 100644 --- a/src/controller/template/quality.ts +++ b/src/controller/template/quality.ts @@ -42,9 +42,9 @@ async function weight(options: TemplateQualityOptions, direction: 'min' | 'max') const result = utils.first(optimized) return { - weight: utils.roundNumber(result.quality.average), direction, - count: result.technologies, + topology: result.topology, + technologies: result.technologies, } } @@ -60,10 +60,10 @@ async function count(options: TemplateQualityOptions, direction: 'min' | 'max') }, }) const all = new Resolver(loaded.graph, loaded.inputs).optimize({all: true}) - const min = Math.min(...all.map(it => it.technologies.count)) + const minCountGroups = Math.min(...all.map(it => it.technologies.count_groups)) const candidates = all - .filter(it => it.technologies.count === min) - .sort((a, b) => a.quality.average - b.quality.average) + .filter(it => it.technologies.count_groups === minCountGroups) + .sort((a, b) => a.technologies.weight_average - b.technologies.weight_average) // TODO: remove this /* @@ -74,20 +74,25 @@ async function count(options: TemplateQualityOptions, direction: 'min' | 'max') console.log( candidates.map(it => ({ technologies: it.technologies.count_each, - quality: it.quality.average, + quality: it.technologies.weight_average, presences: it.getPresences('technology'), })) ) */ - const minResult = utils.first(candidates) - const maxResult = utils.last(candidates) + const min = utils.first(candidates) + const max = utils.last(candidates) return { - count: min, direction, - min: minResult.technologies, - max: maxResult.technologies, + min: { + topology: min.topology, + technologies: min.technologies, + }, + max: { + topology: max.topology, + technologies: max.technologies, + }, } } @@ -107,7 +112,7 @@ async function weightCount(options: TemplateQualityOptions) { const result = utils.first(optimized) return { - weight: utils.roundNumber(result.quality.average), - count: result.technologies, + topology: result.topology, + technologies: result.technologies, } } diff --git a/src/resolver/result.ts b/src/resolver/result.ts index 266f380a9e..9a52670eb5 100644 --- a/src/resolver/result.ts +++ b/src/resolver/result.ts @@ -44,7 +44,7 @@ export class Result { .map(([name, _]) => name) } - get topology(): {count: number; weight: number} { + get topology(): {count: number; weight: number; components: string[]} { /** * Present nodes */ @@ -60,15 +60,24 @@ export class Result { */ const weight = present.reduce((sum, it) => sum + it.weight, 0) - return {count, weight} + /** + * Components (names of present components) + */ + const components = present.map(it => it.name) + + /** + * Result + */ + return {count, weight, components} } get technologies(): { - count: number + count_groups: number count_total: number count_each: {[technology: string]: number} weight: number weight_each: {[technology: string]: number} + weight_average: number assignments: string[] } { /** @@ -80,12 +89,14 @@ export class Result { /** * Count (total number of different technologies, i.e., number of groups by name) */ - const count = Object.values(groups).length + const count_groups = Object.values(groups).length /** * Count Total (total number of all present technologies) */ const count_total = present.length + assert.isNumber(count_total) + if (count_total === 0) throw new Error(`Technology count is 0`) /** * Count Each (number of technologies per group) @@ -109,37 +120,18 @@ export class Result { }, {}) /** - * Presences - */ - const assignments = this.getPresences('technology') - - /** - * Result - */ - return {count, count_total, count_each, weight, weight_each, assignments} - } - - get quality(): {count: number; weight: number; average: number} { - /** - * Count (total number of present technologies) + * Weight Average (average weight per technology */ - const count = this.graph.technologies.filter(it => this.isPresent(it)).length - assert.isNumber(count) - if (count === 0) throw new Error(`Technology count is 0`) + const weight_average = weight / count_total /** - * Weight (sum of all weights of all present technologies) - */ - const weight = this.technologies.weight - - /** - * Average (average weight per technology) + * Presences */ - const average = this.technologies.weight / count + const assignments = this.getPresences('technology') /** * Result */ - return {count, weight, average} + return {count_groups, count_total, count_each, weight, weight_each, weight_average, assignments} } }