From 5efff530885a2ae56dda5d59d7c9094c3be4d8ae Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Wed, 6 Jan 2021 11:17:41 +0100 Subject: [PATCH 1/2] Use native ansible handlers --- .../{{cookiecutter.scenario_name}}/create.yml | 7 +++++-- .../{{cookiecutter.scenario_name}}/destroy.yml | 7 +++++-- molecule_hetznercloud/playbooks/create.yml | 7 +++++-- molecule_hetznercloud/playbooks/destroy.yml | 7 +++++-- .../test/resources/playbooks/hetznercloud/create.yml | 7 +++++-- .../test/resources/playbooks/hetznercloud/destroy.yml | 7 +++++-- 6 files changed, 30 insertions(+), 12 deletions(-) diff --git a/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml b/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml index d964d5b..e138edb 100644 --- a/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml +++ b/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml @@ -73,7 +73,10 @@ - name: Dump instance config copy: - content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" + content: | + # Molecule managed + + {{ instance_conf | to_json | from_json | to_yaml }} dest: "{{ molecule_instance_config }}" when: server.changed | bool @@ -83,5 +86,5 @@ host: "{{ item.address }}" search_regex: SSH delay: 10 - with_items: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" + with_items: "{{ lookup('file', molecule_instance_config) | from_yaml }}" {%- endraw %} diff --git a/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml b/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml index afd44a2..63f2c4b 100644 --- a/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml +++ b/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml @@ -10,7 +10,7 @@ block: - name: Populate instance config from file set_fact: - instance_conf: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" + instance_conf: "{{ lookup('file', molecule_instance_config) | from_yaml }}" skip_instances: false rescue: - name: Populate instance config when file missing @@ -52,7 +52,10 @@ - name: Dump instance config copy: - content: "{{ instance_conf | molecule_to_yaml | molecule_header }}" + content: | + # Molecule managed + + {{ instance_conf | to_json | from_json | to_yaml }} dest: "{{ molecule_instance_config }}" when: server.changed | bool {%- endraw %} diff --git a/molecule_hetznercloud/playbooks/create.yml b/molecule_hetznercloud/playbooks/create.yml index 7bbcfbc..fbdd6fa 100644 --- a/molecule_hetznercloud/playbooks/create.yml +++ b/molecule_hetznercloud/playbooks/create.yml @@ -74,7 +74,10 @@ - name: Dump instance config copy: - content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" + content: | + # Molecule managed + + {{ instance_conf | to_json | from_json | to_yaml }} dest: "{{ molecule_instance_config }}" when: server.changed | bool @@ -84,4 +87,4 @@ host: "{{ item.address }}" search_regex: SSH delay: 10 - with_items: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" + with_items: "{{ lookup('file', molecule_instance_config) | from_yaml }}" diff --git a/molecule_hetznercloud/playbooks/destroy.yml b/molecule_hetznercloud/playbooks/destroy.yml index aae4ed6..2315be7 100644 --- a/molecule_hetznercloud/playbooks/destroy.yml +++ b/molecule_hetznercloud/playbooks/destroy.yml @@ -9,7 +9,7 @@ block: - name: Populate instance config from file set_fact: - instance_conf: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" + instance_conf: "{{ lookup('file', molecule_instance_config) | from_yaml }}" skip_instances: false rescue: - name: Populate instance config when file missing @@ -51,6 +51,9 @@ - name: Dump instance config copy: - content: "{{ instance_conf | molecule_to_yaml | molecule_header }}" + content: | + # Molecule managed + + {{ instance_conf | to_json | from_json | to_yaml }} dest: "{{ molecule_instance_config }}" when: server.changed | bool diff --git a/molecule_hetznercloud/test/resources/playbooks/hetznercloud/create.yml b/molecule_hetznercloud/test/resources/playbooks/hetznercloud/create.yml index bf26ee8..ea1db1c 100644 --- a/molecule_hetznercloud/test/resources/playbooks/hetznercloud/create.yml +++ b/molecule_hetznercloud/test/resources/playbooks/hetznercloud/create.yml @@ -75,7 +75,10 @@ - name: Dump instance config copy: - content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" + content: | + # Molecule managed + + {{ instance_conf | to_json | from_json | to_yaml }} dest: "{{ molecule_instance_config }}" when: server.changed | bool @@ -85,4 +88,4 @@ host: "{{ item.address }}" search_regex: SSH delay: 10 - with_items: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" + with_items: "{{ lookup('file', molecule_instance_config) | from_yaml }}" diff --git a/molecule_hetznercloud/test/resources/playbooks/hetznercloud/destroy.yml b/molecule_hetznercloud/test/resources/playbooks/hetznercloud/destroy.yml index f49f0d7..a325423 100644 --- a/molecule_hetznercloud/test/resources/playbooks/hetznercloud/destroy.yml +++ b/molecule_hetznercloud/test/resources/playbooks/hetznercloud/destroy.yml @@ -9,7 +9,7 @@ block: - name: Populate instance config from file set_fact: - instance_conf: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" + instance_conf: "{{ lookup('file', molecule_instance_config) | from_yaml }}" skip_instances: false rescue: - name: Populate instance config when file missing @@ -52,6 +52,9 @@ - name: Dump instance config copy: - content: "{{ instance_conf | molecule_to_yaml | molecule_header }}" + content: | + # Molecule managed + + {{ instance_conf | to_json | from_json | to_yaml }} dest: "{{ molecule_instance_config }}" when: server.changed | bool From d57f80a496a424aa1b5ce90ee2139a9b1d69921c Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Wed, 6 Jan 2021 11:18:53 +0100 Subject: [PATCH 2/2] Support volumes handling --- integration/molecule/default/molecule.yml | 4 ++ .../{{cookiecutter.scenario_name}}/create.yml | 29 +++++++++++- .../destroy.yml | 23 ++++++++++ molecule_hetznercloud/playbooks/create.yml | 43 +++++++++++++----- molecule_hetznercloud/playbooks/destroy.yml | 23 ++++++++++ .../playbooks/hetznercloud/create.yml | 44 ++++++++++++++----- .../playbooks/hetznercloud/destroy.yml | 28 ++++++++++-- .../unit/model/v2/test_platforms_section.py | 6 +-- 8 files changed, 171 insertions(+), 29 deletions(-) diff --git a/integration/molecule/default/molecule.yml b/integration/molecule/default/molecule.yml index 62700d3..4754c90 100644 --- a/integration/molecule/default/molecule.yml +++ b/integration/molecule/default/molecule.yml @@ -7,6 +7,10 @@ platforms: - name: "molecule-hetznercloud-${INSTANCE_UUID}" server_type: cx11 image: debian-10 + volumes: + name: "molecule-hetznercloud-volume-${INSTANCE_UUID}" + size: 11 + create: true provisioner: name: ansible verifier: diff --git a/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml b/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml index e138edb..71034b8 100644 --- a/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml +++ b/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml @@ -33,7 +33,6 @@ server_type: "{{ item.server_type }}" ssh_keys: - "{{ ssh_key_name }}" - volumes: "{{ item.volumes | default(omit) }}" image: "{{ item.image }}" location: "{{ item.location | default(omit) }}" datacenter: "{{ item.datacenter | default(omit) }}" @@ -53,6 +52,31 @@ retries: 300 with_items: "{{ server.results }}" + - name: Create volume(s) + hcloud_volume: + name: "{{ item.volumes.name | default(item.name) }}" + server: "{{ item.name }}" + location: "{{ item.volumes.location | default(omit) }}" + size: "{{ item.volumes.size | default(10) }}" + api_token: "{{ lookup('env', 'HCLOUD_TOKEN') }}" + state: "present" + with_items: "{{ molecule_yml.platforms }}" + when: + - item.volumes is defined + - item.volumes.create | default(False) | bool + register: volumes + async: 7200 + poll: 0 + + - name: Wait for volume(s) creation to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: hetzner_volumes + until: hetzner_volumes.finished + retries: 300 + when: volumes.changed + with_items: "{{ volumes.results }}" + - name: Populate instance config dict set_fact: instance_conf_dict: { @@ -61,7 +85,8 @@ 'address': "{{ item.hcloud_server.ipv4_address }}", 'user': "{{ ssh_user }}", 'port': "{{ ssh_port }}", - 'identity_file': "{{ ssh_path }}", } + 'identity_file': "{{ ssh_path }}", + 'volumes': "{{ item.item.item.volumes | default({}) }}", } with_items: "{{ hetzner_jobs.results }}" register: instance_config_dict when: server.changed | bool diff --git a/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml b/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml index 63f2c4b..fc93d52 100644 --- a/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml +++ b/molecule_hetznercloud/cookiecutter/scenario/driver/hetznercloud/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml @@ -37,6 +37,29 @@ retries: 300 with_items: "{{ server.results }}" + - name: Destroy volume(s) + hcloud_volume: + name: "{{ item.volumes.name | default(item.instance) }}" + server: "{{ item.instance }}" + api_token: "{{ lookup('env', 'HCLOUD_TOKEN') }}" + state: "absent" + register: volumes + with_items: "{{ instance_conf }}" + when: + - item.volumes is defined + - item.volumes.create | default(False) | bool + async: 7200 + poll: 0 + + - name: Wait for volume(s) deletion to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: hetzner_volumes + until: hetzner_volumes.finished + retries: 300 + when: volumes.changed + with_items: "{{ volumes.results }}" + - name: Remove registered SSH key hcloud_ssh_key: name: "{{ instance_conf[0].ssh_key_name }}" diff --git a/molecule_hetznercloud/playbooks/create.yml b/molecule_hetznercloud/playbooks/create.yml index fbdd6fa..23ee263 100644 --- a/molecule_hetznercloud/playbooks/create.yml +++ b/molecule_hetznercloud/playbooks/create.yml @@ -32,7 +32,6 @@ server_type: "{{ item.server_type }}" ssh_keys: - "{{ ssh_key_name }}" - volumes: "{{ item.volumes | default(omit) }}" image: "{{ item.image }}" location: "{{ item.location | default(omit) }}" datacenter: "{{ item.datacenter | default(omit) }}" @@ -52,17 +51,41 @@ retries: 300 with_items: "{{ server.results }}" + - name: Create volume(s) + hcloud_volume: + name: "{{ item.volumes.name | default(item.name) }}" + server: "{{ item.name }}" + location: "{{ item.volumes.location | default(omit) }}" + size: "{{ item.volumes.size | default(10) }}" + api_token: "{{ lookup('env', 'HCLOUD_TOKEN') }}" + state: "present" + with_items: "{{ molecule_yml.platforms }}" + when: + - item.volumes is defined + - item.volumes.create | default(False) | bool + register: volumes + async: 7200 + poll: 0 + + - name: Wait for volume(s) creation to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: hetzner_volumes + until: hetzner_volumes.finished + retries: 300 + when: volumes.changed + with_items: "{{ volumes.results }}" + - name: Populate instance config dict set_fact: - instance_conf_dict: - { - "instance": "{{ item.hcloud_server.name }}", - "ssh_key_name": "{{ ssh_key_name }}", - "address": "{{ item.hcloud_server.ipv4_address }}", - "user": "{{ ssh_user }}", - "port": "{{ ssh_port }}", - "identity_file": "{{ ssh_path }}", - } + instance_conf_dict: { + 'instance': "{{ item.hcloud_server.name }}", + 'ssh_key_name': "{{ ssh_key_name }}", + 'address': "{{ item.hcloud_server.ipv4_address }}", + 'user': "{{ ssh_user }}", + 'port': "{{ ssh_port }}", + 'identity_file': "{{ ssh_path }}", + 'volumes': "{{ item.item.item.volumes | default({}) }}", } with_items: "{{ hetzner_jobs.results }}" register: instance_config_dict when: server.changed | bool diff --git a/molecule_hetznercloud/playbooks/destroy.yml b/molecule_hetznercloud/playbooks/destroy.yml index 2315be7..16eb0e5 100644 --- a/molecule_hetznercloud/playbooks/destroy.yml +++ b/molecule_hetznercloud/playbooks/destroy.yml @@ -36,6 +36,29 @@ retries: 300 with_items: "{{ server.results }}" + - name: Destroy volume(s) + hcloud_volume: + name: "{{ item.volumes.name | default(item.instance) }}" + server: "{{ item.instance }}" + api_token: "{{ lookup('env', 'HCLOUD_TOKEN') }}" + state: "absent" + register: volumes + with_items: "{{ instance_conf }}" + when: + - item.volumes is defined + - item.volumes.create | default(False) | bool + async: 7200 + poll: 0 + + - name: Wait for volume(s) deletion to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: hetzner_volumes + until: hetzner_volumes.finished + retries: 300 + when: volumes.changed + with_items: "{{ volumes.results }}" + - name: Remove registered SSH key hcloud_ssh_key: name: "{{ instance_conf[0].ssh_key_name }}" diff --git a/molecule_hetznercloud/test/resources/playbooks/hetznercloud/create.yml b/molecule_hetznercloud/test/resources/playbooks/hetznercloud/create.yml index ea1db1c..23ee263 100644 --- a/molecule_hetznercloud/test/resources/playbooks/hetznercloud/create.yml +++ b/molecule_hetznercloud/test/resources/playbooks/hetznercloud/create.yml @@ -23,6 +23,7 @@ hcloud_ssh_key: name: "{{ ssh_key_name }}" public_key: "{{ generated_ssh_key.public_key }}" + api_token: "{{ lookup('env', 'HCLOUD_TOKEN') }}" state: present - name: Create molecule instance(s) @@ -31,7 +32,6 @@ server_type: "{{ item.server_type }}" ssh_keys: - "{{ ssh_key_name }}" - volumes: "{{ item.volumes | default(omit) }}" image: "{{ item.image }}" location: "{{ item.location | default(omit) }}" datacenter: "{{ item.datacenter | default(omit) }}" @@ -51,19 +51,41 @@ retries: 300 with_items: "{{ server.results }}" - # Mandatory configuration for Molecule to function. + - name: Create volume(s) + hcloud_volume: + name: "{{ item.volumes.name | default(item.name) }}" + server: "{{ item.name }}" + location: "{{ item.volumes.location | default(omit) }}" + size: "{{ item.volumes.size | default(10) }}" + api_token: "{{ lookup('env', 'HCLOUD_TOKEN') }}" + state: "present" + with_items: "{{ molecule_yml.platforms }}" + when: + - item.volumes is defined + - item.volumes.create | default(False) | bool + register: volumes + async: 7200 + poll: 0 + + - name: Wait for volume(s) creation to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: hetzner_volumes + until: hetzner_volumes.finished + retries: 300 + when: volumes.changed + with_items: "{{ volumes.results }}" - name: Populate instance config dict set_fact: - instance_conf_dict: - { - "instance": "{{ item.hcloud_server.name }}", - "ssh_key_name": "{{ ssh_key_name }}", - "address": "{{ item.hcloud_server.ipv4_address }}", - "user": "{{ ssh_user }}", - "port": "{{ ssh_port }}", - "identity_file": "{{ ssh_path }}", - } + instance_conf_dict: { + 'instance': "{{ item.hcloud_server.name }}", + 'ssh_key_name': "{{ ssh_key_name }}", + 'address': "{{ item.hcloud_server.ipv4_address }}", + 'user': "{{ ssh_user }}", + 'port': "{{ ssh_port }}", + 'identity_file': "{{ ssh_path }}", + 'volumes': "{{ item.item.item.volumes | default({}) }}", } with_items: "{{ hetzner_jobs.results }}" register: instance_config_dict when: server.changed | bool diff --git a/molecule_hetznercloud/test/resources/playbooks/hetznercloud/destroy.yml b/molecule_hetznercloud/test/resources/playbooks/hetznercloud/destroy.yml index a325423..16eb0e5 100644 --- a/molecule_hetznercloud/test/resources/playbooks/hetznercloud/destroy.yml +++ b/molecule_hetznercloud/test/resources/playbooks/hetznercloud/destroy.yml @@ -36,15 +36,37 @@ retries: 300 with_items: "{{ server.results }}" + - name: Destroy volume(s) + hcloud_volume: + name: "{{ item.volumes.name | default(item.instance) }}" + server: "{{ item.instance }}" + api_token: "{{ lookup('env', 'HCLOUD_TOKEN') }}" + state: "absent" + register: volumes + with_items: "{{ instance_conf }}" + when: + - item.volumes is defined + - item.volumes.create | default(False) | bool + async: 7200 + poll: 0 + + - name: Wait for volume(s) deletion to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: hetzner_volumes + until: hetzner_volumes.finished + retries: 300 + when: volumes.changed + with_items: "{{ volumes.results }}" + - name: Remove registered SSH key hcloud_ssh_key: name: "{{ instance_conf[0].ssh_key_name }}" + api_token: "{{ lookup('env', 'HCLOUD_TOKEN') }}" state: absent when: - not skip_instances - - instance_conf # must contain at least one instance - - # Mandatory configuration for Molecule to function. + - instance_conf | length # must contain at least one instance - name: Populate instance config set_fact: diff --git a/molecule_hetznercloud/test/unit/model/v2/test_platforms_section.py b/molecule_hetznercloud/test/unit/model/v2/test_platforms_section.py index 81cc274..b3f6df0 100644 --- a/molecule_hetznercloud/test/unit/model/v2/test_platforms_section.py +++ b/molecule_hetznercloud/test/unit/model/v2/test_platforms_section.py @@ -10,7 +10,7 @@ def _model_platform_hetznercloud_section_data(): { "name": "instance", "server_type": "", - "volumes": [""], + "volumes": {}, "image": "", "location": "", "datacenter": "", @@ -35,7 +35,7 @@ def _model_platforms_hetznercloud_errors_section_data(): { "name": 0, "server_type": 0, - "volumes": {}, + "volumes": [], "image": 0, "location": 0, "datacenter": 0, @@ -57,7 +57,7 @@ def test_platforms_hetznercloud_has_errors(_config): { "name": ["must be of string type"], "server_type": ["must be of string type"], - "volumes": ["must be of list type"], + "volumes": ["must be of dict type"], "image": ["must be of string type"], "location": ["must be of string type"], "datacenter": ["must be of string type"],