diff --git a/docs/docs/variability4tosca/specification/index.md b/docs/docs/variability4tosca/specification/index.md index b133002ecf..f2a6f8dcfd 100644 --- a/docs/docs/variability4tosca/specification/index.md +++ b/docs/docs/variability4tosca/specification/index.md @@ -962,14 +962,15 @@ The following intrinsic functions can be used inside a variability expression. The following logical operators can be used inside a logic expression. -| Keyname | Input | Output | Description | -|----------|---------------------------------------------|---------|----------------------------------------------------| -| and | List(BooleanExpression) | Boolean | Evaluates if all values are `true`. | -| or | List(BooleanExpression) | Boolean | Evaluates if at least one value is `true`. | -| not | BooleanExpression | Boolean | Negates the given value. | -| xor | List(BooleanExpression) | Boolean | Evaluates if exactly one value is `true`. | -| implies | Tuple(BooleanExpression, BooleanExpression) | Boolean | Evaluates if first value implies the second value. | -| amo | List(BooleanExpression) | Boolean | Evaluates if at most one value is `true`. | +| Keyname | Input | Output | Description | +|---------|---------------------------------------------|---------|----------------------------------------------------| +| and | List(BooleanExpression) | Boolean | Evaluates if all values are `true`. | +| or | List(BooleanExpression) | Boolean | Evaluates if at least one value is `true`. | +| not | BooleanExpression | Boolean | Negates the given value. | +| xor | List(BooleanExpression) | Boolean | Evaluates if an odd number of arguments is `true`. | +| exo | List(BooleanExpression) | Boolean | Evaluates if exactly one value is `true`. | +| implies | Tuple(BooleanExpression, BooleanExpression) | Boolean | Evaluates if first value implies the second value. | +| amo | List(BooleanExpression) | Boolean | Evaluates if at most one value is `true`. | ### Arithmetic Operators 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---industry/variable-service-template.yaml b/examples/unfurl-technology---industry/variable-service-template.yaml index dc0c156954..3737188465 100644 --- a/examples/unfurl-technology---industry/variable-service-template.yaml +++ b/examples/unfurl-technology---industry/variable-service-template.yaml @@ -136,13 +136,6 @@ topology_template: is_customer: {equal: [{variability_input: env}, CUSTOMER]} is_development: {equal: [{variability_input: env}, DEVELOPMENT]} - # TODO: remove these - options: - #technology_constraint: false - #required_technology_check: false - #required_artifact_constraint: false - #expected_artifact_check: true - inputs: env: type: string 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/cli/program.ts b/src/cli/program.ts index a1bb8c3829..fb62ebbaab 100644 --- a/src/cli/program.ts +++ b/src/cli/program.ts @@ -8,6 +8,7 @@ import std from '#std' import hae from '#utils/hae' import open from '#utils/open' import {Command, Option} from 'commander' +import * as util from 'node:util' export const program = new Command() @@ -497,7 +498,7 @@ template ) .action( hae.exit(async options => { - std.out(await Controller.template.quality(options)) + std.out(util.inspect(await Controller.template.quality(options), {depth: null})) }) ) @@ -1137,7 +1138,7 @@ utils utils .command('rules') .description('returns technology rules') - .addOption(new Option('--format [string]', 'output format').default('yaml').choices(['yaml', 'json'])) + .addOption(new Option('--format [string]', 'output format').default('yaml').choices(['yaml', 'json', 'latex'])) .action( hae.exit(async options => { std.out(await Controller.utils.rules(options)) diff --git a/src/controller/study/technology.ts b/src/controller/study/technology.ts index 8bca98942d..b8a7268846 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, - non_expert: [quality.min_weight, quality.max_weight], - random: [quality.min_weight, quality.max_weight], - counting: [quality.min_count.min, quality.min_count.max], - quality: quality.max_weight, - quality_counting: quality.max_weight_min_count, + expert: utils.roundNumber(quality.max_weight.weight_average), + non_expert: [ + utils.roundNumber(quality.min_weight.weight_average), + utils.roundNumber(quality.max_weight.weight_average), + ], + random: [ + utils.roundNumber(quality.min_weight.weight_average), + utils.roundNumber(quality.max_weight.weight_average), + ], + counting: [ + utils.roundNumber(quality.min_count.min_quality.weight_average), + utils.roundNumber(quality.min_count.max_quality.weight_average), + ], + quality: utils.roundNumber(quality.max_weight.weight_average), + quality_counting: utils.roundNumber(quality.max_weight_min_count.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 efeade716b..3c26faccf5 100644 --- a/src/controller/template/quality.ts +++ b/src/controller/template/quality.ts @@ -38,7 +38,10 @@ async function weight(options: TemplateQualityOptions, direction: 'min' | 'max') }) const optimized = new Resolver(loaded.graph, loaded.inputs).optimize() if (optimized.length !== 1) throw new Error(`Did not return correct quality`) - return utils.roundNumber(utils.first(optimized).quality.average) + + const result = utils.first(optimized) + + return result.technologies } async function count(options: TemplateQualityOptions, direction: 'min' | 'max') { @@ -53,10 +56,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 /* @@ -67,15 +70,18 @@ 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 min = utils.first(candidates) + const max = utils.last(candidates) + return { - min: utils.roundNumber(utils.first(candidates).quality.average), - max: utils.roundNumber(utils.last(candidates).quality.average), + min_quality: min.technologies, + max_quality: max.technologies, } } @@ -91,5 +97,8 @@ async function weightCount(options: TemplateQualityOptions) { }) const optimized = new Resolver(loaded.graph, loaded.inputs).optimize() if (optimized.length !== 1) throw new Error(`Did not return correct quality`) - return utils.roundNumber(utils.first(optimized).quality.average) + + const result = utils.first(optimized) + + return result.technologies } diff --git a/src/controller/utils/rules.ts b/src/controller/utils/rules.ts index 498550267a..1acf68185a 100644 --- a/src/controller/utils/rules.ts +++ b/src/controller/utils/rules.ts @@ -7,5 +7,7 @@ export type RuleOptions = { export default async function (options: RuleOptions) { options.format = options.format ?? 'yaml' - return files.toFormat(Registry.rules, options.format) + return files.toFormat(Registry.rules, options.format, { + latex: {headers: ['component', 'artifact', 'hosting', 'technology', 'weight']}, + }) } diff --git a/src/enricher/constraints.ts b/src/enricher/constraints.ts index a63287aa8b..f8f3b0960b 100644 --- a/src/enricher/constraints.ts +++ b/src/enricher/constraints.ts @@ -127,7 +127,7 @@ export class ConstraintEnricher { if (this.graph.options.constraints.hostingStack) { for (const node of this.graph.nodes.filter(it => it.hasHost)) { const hostings = node.outgoing.filter(it => it.isHostedOn()) - const consequence = hostings.length === 1 ? hostings[0].id : {xor: hostings.map(it => it.id)} + const consequence = hostings.length === 1 ? hostings[0].id : {exo: hostings.map(it => it.id)} this.graph.addConstraint({implies: [node.id, consequence]}) } } @@ -155,7 +155,7 @@ export class ConstraintEnricher { if (this.graph.options.constraints.requiredArtifact) { for (const node of this.graph.nodes) { if (utils.isEmpty(node.artifacts)) continue - const consequence = {xor: node.artifacts.map(it => it.id)} + const consequence = {exo: node.artifacts.map(it => it.id)} this.graph.addConstraint({implies: [node.id, consequence]}) } } @@ -166,7 +166,7 @@ export class ConstraintEnricher { if (this.graph.options.constraints.technology) { for (const node of this.graph.nodes.filter(it => !utils.isEmpty(it.technologies))) { const consequence = - node.technologies.length === 1 ? node.technologies[0].id : {xor: node.technologies.map(it => it.id)} + node.technologies.length === 1 ? node.technologies[0].id : {exo: node.technologies.map(it => it.id)} this.graph.addConstraint({implies: [node.id, consequence]}) } } diff --git a/src/graph/utils.ts b/src/graph/utils.ts index 950d3884f2..362911a25f 100644 --- a/src/graph/utils.ts +++ b/src/graph/utils.ts @@ -65,6 +65,7 @@ export function simplify(conditions: LogicExpression): LogicExpression { } // TODO: xor + // TODO: exo // TODO: amo // TODO: implies diff --git a/src/resolver/result.ts b/src/resolver/result.ts index 99c26d513a..a33cf00c9e 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,25 @@ 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_total: number count_each: {[technology: string]: number} - weight: number + count_groups: number + weight_total: number weight_each: {[technology: string]: number} + weight_average: number + assignments: string[] } { /** * Present technologies @@ -79,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) @@ -97,7 +109,7 @@ export class Result { /** * Weight (sum of all weights of all present technologies) */ - const weight = utils.sum(present.map(it => it.weight)) + const weight_total = utils.sum(present.map(it => it.weight)) /** * Weight Each (sum of all weight in a group of present technology) @@ -108,32 +120,18 @@ export class Result { }, {}) /** - * Result - */ - return {count, count_total, count_each, weight, weight_each} - } - - get quality(): {count: number; weight: number; average: number} { - /** - * Count (total number of present technologies) - */ - const count = this.graph.technologies.filter(it => this.isPresent(it)).length - assert.isNumber(count) - if (count === 0) throw new Error(`Technology count is 0`) - - /** - * Weight (sum of all weights of all present technologies) + * Weight Average (average weight per technology */ - const weight = this.technologies.weight + const weight_average = weight_total / count_total /** - * 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_total, weight_each, weight_average, assignments} } } diff --git a/src/resolver/solver.ts b/src/resolver/solver.ts index 47cd5c924e..581697b0b0 100644 --- a/src/resolver/solver.ts +++ b/src/resolver/solver.ts @@ -407,7 +407,14 @@ export default class Solver { * xor */ if (check.isDefined(expression.xor)) { - return MiniSat.exactlyOne(expression.xor.map(it => this.transformLogicExpression(it, context))) + return MiniSat.xor(expression.xor.map(it => this.transformLogicExpression(it, context))) + } + + /** + * exo + */ + if (check.isDefined(expression.exo)) { + return MiniSat.exactlyOne(expression.exo.map(it => this.transformLogicExpression(it, context))) } /** diff --git a/src/specification/variability.ts b/src/specification/variability.ts index 7a3b27c707..261ebe8237 100644 --- a/src/specification/variability.ts +++ b/src/specification/variability.ts @@ -312,6 +312,7 @@ export type LogicExpression = or?: LogicExpression[] not?: LogicExpression xor?: LogicExpression[] + exo?: LogicExpression[] implies?: [LogicExpression, LogicExpression] amo?: LogicExpression[] diff --git a/src/technologies/plugins/rules/.template.ts b/src/technologies/plugins/rules/.template.ts index 95ff20d7f3..2e769a002b 100644 --- a/src/technologies/plugins/rules/.template.ts +++ b/src/technologies/plugins/rules/.template.ts @@ -3,7 +3,7 @@ import {MetadataGenerated} from '#technologies/plugins/rules/utils/utils' const generator: ImplementationGenerator = { reason: '', - weight: 0, + count: 0, component: 'service.application', technology: 'ansible', artifact: 'zip.archive', diff --git a/src/utils/files.ts b/src/utils/files.ts index 040fe0bbbb..682b174179 100644 --- a/src/utils/files.ts +++ b/src/utils/files.ts @@ -163,16 +163,68 @@ export async function loadXML(file: string) { return (await xml2js.parseStringPromise(loadFile(file) /*, options */)) as T } -export function toFormat(obj: any, format: string) { +export function toFormat(obj: any, format: string, options: {latex?: LatexOptions} = {}) { if (format === 'yaml') return toYAML(obj) if (format === 'json') return toJSON(obj) if (format === 'ini') return toINI(obj) if (format === 'env') return toENV(obj) if (format === 'xml') return toXML(obj) + if (format === 'latex') return toLatex(obj, options.latex) throw new Error(`Format "${format}" not supported`) } +export type LatexOptions = { + headers?: string[] +} + +export function toLatex(obj: any, options: LatexOptions = {}) { + assert.isArray(obj) + // TODO: this is dirty + const list = obj as {[key: string]: any}[] + + // Collect all possible keys + const defaultKeys = () => { + const dk: string[] = [] + list.forEach(item => { + Object.keys(item).forEach(key => keys.push(key)) + }) + return dk + } + + const keys = options.headers ?? defaultKeys() + + const data = [] + + /** + * Header + */ + data.push('\\toprule') + data.push('index & ' + Array.from(keys).join(' & ') + '\\\\') + data.push('\\midrule') + + /** + * Entries + */ + list.forEach((item, index) => { + const tmp = [index] + for (const key of keys) { + const raw = item[key] + // TODO: not latex safe + const value = JSON.stringify(raw) + tmp.push(raw) + } + data.push(tmp.join(' & ') + '\\\\') + }) + + /** + * Footer + */ + data.push('\\bottomrule') + + return data.join('\n') +} + export function formatYAML(obj: any) { return prettier.format(obj, { parser: 'yaml', diff --git a/tasks/docs/generate/rules/technologies.ts b/tasks/docs/generate/rules/technologies.ts index 7fab2567e3..7bb0ef0ddb 100644 --- a/tasks/docs/generate/rules/technologies.ts +++ b/tasks/docs/generate/rules/technologies.ts @@ -9,7 +9,7 @@ const ansible: TechnologyDescription = { id: 'ansible', name: 'Ansible', description: - 'Ansible is an open-source automation tool primarily used for configuration management, application deployment, and task automation. It allows IT administrators and DevOps teams to manage software on servers using SSH, without the need for agents on target nodes. Ansible uses simple, human-readable YAML files called playbooks to define tasks and configurations, enabling consistent management of IT environments across multiple servers. Its main purpose is to simplify the management of software configurations, reduce manual effort, and ensure consistency and reliability in IT operations, making it an ideal tool for automating repetitive tasks and orchestrating complex workflows across diverse environments.', + 'Ansible is an automation tool primarily used for configuration management, application deployment, and task automation. It allows system administrators and DevOps teams to manage software on servers using SSH, without the need for agents on target nodes. Ansible uses simple, human-readable YAML files called playbooks to define tasks and configurations, enabling consistent management of IT environments across multiple servers.', link: 'https://ansible.com', } @@ -17,7 +17,7 @@ const terraform: TechnologyDescription = { id: 'terraform', name: 'Terraform', description: - 'Terraform is an open-source infrastructure as code (IaC) tool developed by HashiCorp that allows users to define, provision, and manage cloud infrastructure in a consistent, automated, and reproducible way. Using a declarative configuration language called HashiCorp Configuration Language (HCL) or JSON, Terraform enables users to define infrastructure components such as virtual machines, networks, and storage in human-readable configuration files. It supports a wide range of cloud providers, including AWS, Azure, Google Cloud, and many others, allowing for seamless multi-cloud management. By applying these configurations, Terraform creates and manages the defined resources through APIs, making it a powerful tool for automating infrastructure deployment, scaling, and version control. However, Terraform is specifically designed for managing infrastructure and is not intended for managing software on remote targets, which is outside its primary scope.', + 'Terraform is an infrastructure as code (IaC) tool that allows users to define, provision, and manage cloud infrastructure in a consistent, automated, and reproducible way. Using a declarative configuration language called HashiCorp Configuration Language (HCL), Terraform enables users to define infrastructure components such as virtual machines, networks, and storage in human-readable configuration files. It supports a wide range of cloud providers, including AWS, Azure, Google Cloud, and many others, allowing for seamless multi-cloud management. By applying these configurations, Terraform creates and manages the defined resources through APIs.', link: 'https://terraform.io', } @@ -25,7 +25,7 @@ const kubernetes: TechnologyDescription = { id: 'kubernetes', name: 'Kubernetes', description: - 'Kubernetes, also known as K8s, is an open-source system for automating the deployment, scaling, and management of containerized applications, offering production-grade container orchestration. It provides a robust platform for running and managing applications in clusters of servers, ensuring high availability, scalability, and efficient resource utilization. Kubernetes allows users to define the desired state of their applications using declarative manifests, which specify the configuration, deployment, and management of containerized workloads. By continuously monitoring and adjusting the cluster to match these desired states, Kubernetes simplifies the application deployment process, supports automated rollouts and rollbacks, and ensures the self-healing of applications, making it a critical tool for modern software delivery and operational efficiency.', + 'Kubernetes is a system for automating the deployment, scaling, and management of containerized applications, offering production-grade container orchestration. It provides a platform for running and managing applications in clusters of servers, ensuring high availability, scalability, and efficient resource utilization. Kubernetes allows users to define the desired state of their applications using declarative manifests, which specify the configuration, deployment, and management of containerized workloads. By continuously monitoring and adjusting the cluster to match these desired states, Kubernetes simplifies the application deployment process, supports automated rollouts and rollbacks, and ensures the self-healing of applications.', link: 'https://kubernetes.io', } @@ -33,7 +33,7 @@ const compose: TechnologyDescription = { id: 'compose', name: 'Docker Compose', description: - 'Docker Compose is a tool that enables the definition and running of multi-container applications on a Docker Engine, using a single YAML configuration file. It streamlines the management of complex applications by simplifying the control of services, networks, and volumes, allowing developers to manage the entire stack effortlessly. Compose is particularly suited for development, testing, and single-host deployments, providing a consistent environment across various stages of the application lifecycle. However, it is limited to working within the Docker ecosystem, as it only deploys on Docker Engine, making it an ideal choice for those heavily invested in Docker-based workflows.', + 'Docker Compose is a tool that enables the definition and running of multi-container applications on a Docker Engine, using a single YAML configuration file. It allows the management of services, networks, and volumes, in a declarative manner. Compose is particularly suited for single-host deployments, providing a consistent environment across various stages of the application lifecycle. However, it is limited to working within the Docker ecosystem.', link: 'https://docs.docker.com/compose', } diff --git a/tests/conformance/boolean-operators/xor-false-all/expected.yaml b/tests/conformance/boolean-operators/exo-false-all/expected.yaml similarity index 100% rename from tests/conformance/boolean-operators/xor-false-all/expected.yaml rename to tests/conformance/boolean-operators/exo-false-all/expected.yaml diff --git a/tests/conformance/boolean-operators/xor-false-all/template.yaml b/tests/conformance/boolean-operators/exo-false-all/template.yaml similarity index 77% rename from tests/conformance/boolean-operators/xor-false-all/template.yaml rename to tests/conformance/boolean-operators/exo-false-all/template.yaml index 5982559172..96282329b3 100644 --- a/tests/conformance/boolean-operators/xor-false-all/template.yaml +++ b/tests/conformance/boolean-operators/exo-false-all/template.yaml @@ -7,4 +7,4 @@ topology_template: node_templates: container: type: container - conditions: {xor: [false, false, false, false]} + conditions: {exo: [false, false, false, false]} diff --git a/tests/conformance/boolean-operators/xor-false-all/test.yaml b/tests/conformance/boolean-operators/exo-false-all/test.yaml similarity index 73% rename from tests/conformance/boolean-operators/xor-false-all/test.yaml rename to tests/conformance/boolean-operators/exo-false-all/test.yaml index 560f40c2d0..3d8aaf76b7 100644 --- a/tests/conformance/boolean-operators/xor-false-all/test.yaml +++ b/tests/conformance/boolean-operators/exo-false-all/test.yaml @@ -1,2 +1,2 @@ -name: 'Operator "xor": all false -> false' +name: 'Operator "exo": all false -> false' description: Assigns "false" to the property "value" of the node "container" since the expression evaluates to "false". diff --git a/tests/conformance/boolean-operators/xor-true-all/expected.yaml b/tests/conformance/boolean-operators/exo-true-all/expected.yaml similarity index 100% rename from tests/conformance/boolean-operators/xor-true-all/expected.yaml rename to tests/conformance/boolean-operators/exo-true-all/expected.yaml diff --git a/tests/conformance/boolean-operators/xor-true-all/template.yaml b/tests/conformance/boolean-operators/exo-true-all/template.yaml similarity index 79% rename from tests/conformance/boolean-operators/xor-true-all/template.yaml rename to tests/conformance/boolean-operators/exo-true-all/template.yaml index fad040269f..55bf8e85c2 100644 --- a/tests/conformance/boolean-operators/xor-true-all/template.yaml +++ b/tests/conformance/boolean-operators/exo-true-all/template.yaml @@ -7,4 +7,4 @@ topology_template: node_templates: container: type: container - conditions: {xor: [true, true, true, true]} + conditions: {exo: [true, true, true, true]} diff --git a/tests/conformance/boolean-operators/xor-true-all/test.yaml b/tests/conformance/boolean-operators/exo-true-all/test.yaml similarity index 74% rename from tests/conformance/boolean-operators/xor-true-all/test.yaml rename to tests/conformance/boolean-operators/exo-true-all/test.yaml index 207603f99a..0b98dd4f8c 100644 --- a/tests/conformance/boolean-operators/xor-true-all/test.yaml +++ b/tests/conformance/boolean-operators/exo-true-all/test.yaml @@ -1,2 +1,2 @@ -name: 'Operator "xor": all true -> false' +name: 'Operator "exo": all true -> false' description: Assigns "false" to the property "value" of the node "container" since the expression evaluates to "false". diff --git a/tests/conformance/boolean-operators/xor-true/expected.yaml b/tests/conformance/boolean-operators/exo-true/expected.yaml similarity index 100% rename from tests/conformance/boolean-operators/xor-true/expected.yaml rename to tests/conformance/boolean-operators/exo-true/expected.yaml diff --git a/tests/conformance/boolean-operators/xor-true/template.yaml b/tests/conformance/boolean-operators/exo-true/template.yaml similarity index 78% rename from tests/conformance/boolean-operators/xor-true/template.yaml rename to tests/conformance/boolean-operators/exo-true/template.yaml index fc58ad65c7..72bf5ce757 100644 --- a/tests/conformance/boolean-operators/xor-true/template.yaml +++ b/tests/conformance/boolean-operators/exo-true/template.yaml @@ -7,4 +7,4 @@ topology_template: node_templates: container: type: container - conditions: {xor: [true, false, false, false]} + conditions: {exo: [true, false, false, false]} diff --git a/tests/conformance/boolean-operators/xor-true/test.yaml b/tests/conformance/boolean-operators/exo-true/test.yaml similarity index 74% rename from tests/conformance/boolean-operators/xor-true/test.yaml rename to tests/conformance/boolean-operators/exo-true/test.yaml index 0da461eb1f..baf1e002aa 100644 --- a/tests/conformance/boolean-operators/xor-true/test.yaml +++ b/tests/conformance/boolean-operators/exo-true/test.yaml @@ -1,2 +1,2 @@ -name: 'Operator "xor": One ture -> true' +name: 'Operator "exo": One ture -> true' description: Assigns "true" to the property "value" of the node "container" since the expression evaluates to "true".