summaryrefslogtreecommitdiffstats
path: root/ansible_collections/vultr
diff options
context:
space:
mode:
Diffstat (limited to 'ansible_collections/vultr')
-rw-r--r--ansible_collections/vultr/cloud/.ansible-lint9
-rw-r--r--ansible_collections/vultr/cloud/.github/dependabot.yml8
-rw-r--r--ansible_collections/vultr/cloud/.github/workflows/integration.yml91
-rw-r--r--ansible_collections/vultr/cloud/.github/workflows/publish.yml38
-rw-r--r--ansible_collections/vultr/cloud/.github/workflows/sanity.yml43
-rw-r--r--ansible_collections/vultr/cloud/.github/workflows/unit.yml71
-rw-r--r--ansible_collections/vultr/cloud/.gitignore4
-rw-r--r--ansible_collections/vultr/cloud/.yamllint33
-rw-r--r--ansible_collections/vultr/cloud/CHANGELOG.rst157
-rw-r--r--ansible_collections/vultr/cloud/CONTRIBUTING.md6
-rw-r--r--ansible_collections/vultr/cloud/COPYING621
-rw-r--r--ansible_collections/vultr/cloud/FILES.json2301
-rw-r--r--ansible_collections/vultr/cloud/MANIFEST.json33
-rw-r--r--ansible_collections/vultr/cloud/README.md120
-rw-r--r--ansible_collections/vultr/cloud/changelogs/.gitignore1
-rw-r--r--ansible_collections/vultr/cloud/changelogs/changelog.yaml198
-rw-r--r--ansible_collections/vultr/cloud/changelogs/config.yaml29
-rw-r--r--ansible_collections/vultr/cloud/changelogs/fragments/.keep0
-rw-r--r--ansible_collections/vultr/cloud/codecov.yml5
-rw-r--r--ansible_collections/vultr/cloud/meta/runtime.yml29
-rw-r--r--ansible_collections/vultr/cloud/plugins/doc_fragments/__init__.py0
-rw-r--r--ansible_collections/vultr/cloud/plugins/doc_fragments/vultr_v2.py51
-rw-r--r--ansible_collections/vultr/cloud/plugins/inventory/vultr.py348
-rw-r--r--ansible_collections/vultr/cloud/plugins/module_utils/vultr_v2.py368
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/__init__.py0
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/account_info.py117
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/block_storage.py271
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/block_storage_info.py139
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/dns_domain.py155
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/dns_domain_info.py109
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/dns_record.py267
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/firewall_group.py138
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/firewall_group_info.py114
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/firewall_rule.py297
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/firewall_rule_info.py162
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/instance.py739
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/instance_info.py271
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/os_info.py115
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/plan_info.py140
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/plan_metal_info.py153
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/region_info.py106
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/reserved_ip.py290
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/snapshot.py218
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/snapshot_info.py132
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/ssh_key.py148
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/ssh_key_info.py117
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/startup_script.py196
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/startup_script_info.py120
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/user.py229
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/user_info.py125
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/vpc.py182
-rw-r--r--ansible_collections/vultr/cloud/plugins/modules/vpc_info.py122
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/cloud-config-vultr.ini.template12
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/account_info/aliases2
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/account_info/tasks/main.yml27
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage/defaults/main.yml16
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/failures.yml21
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/main.yml16
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/tests.yml165
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/tests_attach_to_server.yml151
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/defaults/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/tasks/tests.yml36
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/aliases1
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/defaults/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_block_storage.yml29
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_dns_domain.yml29
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_firewall_group.yml28
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_instance.yml29
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_network.yml29
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_reserved_ip.yml29
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_snapshot.yml29
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_ssh_key.yml29
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_startup_script.yml29
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_user.yml29
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_vpc.yml33
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/common/aliases1
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/common/default/main.yml4
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/defaults/main.yml4
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/tasks/main.yml13
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/tasks/tests.yml138
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/defaults/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/tasks/main.yml13
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/tasks/tests.yml27
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/defaults/main.yml38
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/create_record.yml62
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/main.yml13
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/record.yml6
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/remove_record.yml114
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/test_fail_multiple.yml78
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/tests.yml12
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/update_record.yml70
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/defaults/main.yml4
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/tasks/tests.yml86
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/defaults/main.yml2
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/tasks/tests.yml34
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/defaults/main.yml40
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/main.yml8
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/rule_absent.yml62
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/rule_present.yml62
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/tests.yml28
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/defaults/main.yml2
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/tasks/tests.yml45
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/defaults/main.yml95
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/absent.yml38
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/failures.yml55
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/main.yml16
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/present.yml190
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/reinstall.yml28
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/stop-start.yml78
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/tests.yml70
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance_info/defaults/main.yml23
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance_info/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance_info/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/instance_info/tasks/tests.yml62
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/os_info/aliases1
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/os_info/tasks/main.yml22
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/plan_info/aliases1
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/plan_info/tasks/main.yml22
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/plan_metal_info/aliases1
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/plan_metal_info/tasks/main.yml23
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/region_info/aliases1
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/region_info/tasks/main.yml22
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/aliases0
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/defaults/main.yml9
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/tasks/main.yml10
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/tasks/tests.yml240
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot/defaults/main.yml15
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/absent.yml35
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/failures.yml33
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/main.yml10
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/present.yml36
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/tests.yml35
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/defaults/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/tasks/tests.yml34
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/defaults/main.yml6
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/tasks/tests.yml140
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/defaults/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/tasks/tests.yml44
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script/defaults/main.yml6
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script/tasks/tests.yml140
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/defaults/main.yml4
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/tasks/tests.yml35
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user/defaults/main.yml4
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user/tasks/tests.yml218
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user_info/defaults/main.yml10
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user_info/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user_info/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/user_info/tasks/tests.yml34
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc/defaults/main.yml5
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc/tasks/tests.yml112
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/aliases3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/defaults/main.yml5
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/meta/main.yml3
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/tasks/main.yml7
-rw-r--r--ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/tasks/tests.yml36
-rw-r--r--ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/empty_vultr_inventory.json10
-rw-r--r--ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/unauthorized_vultr_inventory.json4
-rw-r--r--ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory.json275
-rw-r--r--ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory_page1.json179
-rw-r--r--ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory_page2.json116
-rw-r--r--ansible_collections/vultr/cloud/tests/unit/plugins/inventory/test_vultr.py233
210 files changed, 14535 insertions, 0 deletions
diff --git a/ansible_collections/vultr/cloud/.ansible-lint b/ansible_collections/vultr/cloud/.ansible-lint
new file mode 100644
index 000000000..e2b2e66b3
--- /dev/null
+++ b/ansible_collections/vultr/cloud/.ansible-lint
@@ -0,0 +1,9 @@
+---
+parseable: true
+skip_list:
+ - ANSIBLE0010
+use_default_rules: true
+verbosity: 1
+exclude_paths:
+ - ./tests/
+ - ./plugins
diff --git a/ansible_collections/vultr/cloud/.github/dependabot.yml b/ansible_collections/vultr/cloud/.github/dependabot.yml
new file mode 100644
index 000000000..607e7e1a2
--- /dev/null
+++ b/ansible_collections/vultr/cloud/.github/dependabot.yml
@@ -0,0 +1,8 @@
+# Set update schedule for GitHub Actions
+---
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/ansible_collections/vultr/cloud/.github/workflows/integration.yml b/ansible_collections/vultr/cloud/.github/workflows/integration.yml
new file mode 100644
index 000000000..689891737
--- /dev/null
+++ b/ansible_collections/vultr/cloud/.github/workflows/integration.yml
@@ -0,0 +1,91 @@
+---
+name: Collection integration
+
+on:
+ pull_request:
+ types: [labeled]
+ push:
+ branches:
+ - main
+ paths:
+ - ".github/workflows/integration.yml"
+ - "plugins/**"
+ - "tests/integration/**"
+ schedule:
+ - cron: 56 3 * * 2 # Run weekly
+
+jobs:
+ integration-test:
+ name: Integration test Ansible ${{ matrix.ansible }} Py${{ matrix.python }}
+ if: ${{ github.event.label.name == 'automation' || github.ref_name == 'main' }}
+ runs-on: ubuntu-20.04
+ defaults:
+ run:
+ working-directory: ansible_collections/vultr/cloud
+ strategy:
+ max-parallel: 1
+ fail-fast: false
+ matrix:
+ ansible:
+ - stable-2.14
+ python:
+ - "3.10"
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v3
+ with:
+ path: ansible_collections/vultr/cloud
+
+ - name: Set up Python ${{ matrix.python }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python }}
+
+ - name: Install ansible-base (${{ matrix.ansible }})
+ run: |
+ python -m pip install --upgrade pip
+ pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
+
+ - name: Build and install collection
+ run: |
+ ansible-galaxy collection build .
+ ansible-galaxy collection install *.gz
+
+ - name: Add config file
+ env:
+ VULTR_CONFIG_FILE: ${{ secrets.VULTR_CONFIG_FILE }}
+ run: |
+ echo "$VULTR_CONFIG_FILE" > tests/integration/cloud-config-vultr.ini
+
+ - name: Ensure no other integration test is currently running
+ uses: softprops/turnstyle@v1
+ timeout-minutes: 60
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ same-branch-only: false
+
+ - name: Run the tests
+ run: >-
+ ansible-test
+ integration
+ --docker
+ -v
+ --color
+ --continue-on-error
+ --diff
+ --python ${{ matrix.python }}
+ --coverage
+ cloud/vultr/
+
+ - name: Generate coverage report
+ run: >-
+ ansible-test
+ coverage xml
+ -v
+ --requirements
+ --group-by command
+ --group-by version
+ - uses: codecov/codecov-action@v3
+ with:
+ fail_ci_if_error: false
diff --git a/ansible_collections/vultr/cloud/.github/workflows/publish.yml b/ansible_collections/vultr/cloud/.github/workflows/publish.yml
new file mode 100644
index 000000000..8e13d6925
--- /dev/null
+++ b/ansible_collections/vultr/cloud/.github/workflows/publish.yml
@@ -0,0 +1,38 @@
+---
+name: Upload release to Galaxy
+
+on:
+ release:
+ types: [created]
+
+jobs:
+ call-workflow-sanity:
+ uses: ./.github/workflows/sanity.yml
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: call-workflow-sanity
+ defaults:
+ run:
+ working-directory: ansible_collections/vultr/cloud
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ path: ansible_collections/vultr/cloud
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.x"
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install ansible
+
+ - name: Build and publish
+ env:
+ ANSIBLE_GALAXY_API_KEY: ${{ secrets.ANSIBLE_GALAXY_API_KEY }}
+ run: |
+ ansible-galaxy collection build .
+ ansible-galaxy collection publish *.tar.gz --api-key $ANSIBLE_GALAXY_API_KEY
diff --git a/ansible_collections/vultr/cloud/.github/workflows/sanity.yml b/ansible_collections/vultr/cloud/.github/workflows/sanity.yml
new file mode 100644
index 000000000..386568562
--- /dev/null
+++ b/ansible_collections/vultr/cloud/.github/workflows/sanity.yml
@@ -0,0 +1,43 @@
+---
+name: Sanity
+
+on:
+ push:
+ branches:
+ - main
+ schedule:
+ - cron: "5 12 * * *"
+ pull_request:
+ workflow_call:
+ workflow_dispatch:
+
+jobs:
+ sanity:
+ name: Sanity (${{ matrix.ansible }})
+ runs-on: ubuntu-20.04
+ defaults:
+ run:
+ working-directory: ansible_collections/vultr/cloud
+ strategy:
+ matrix:
+ ansible:
+ - stable-2.12
+ - stable-2.13
+ - stable-2.14
+ - devel
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v3
+ with:
+ path: ansible_collections/vultr/cloud
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.10"
+
+ - name: Install ansible-base (${{ matrix.ansible }})
+ run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
+
+ - name: Run sanity tests
+ run: ansible-test sanity --docker -v --color
diff --git a/ansible_collections/vultr/cloud/.github/workflows/unit.yml b/ansible_collections/vultr/cloud/.github/workflows/unit.yml
new file mode 100644
index 000000000..667b58c30
--- /dev/null
+++ b/ansible_collections/vultr/cloud/.github/workflows/unit.yml
@@ -0,0 +1,71 @@
+---
+name: Unit tests
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+ paths:
+ - '.github/workflows/unit.yml'
+ - 'plugins/**'
+ - 'tests/unit/**'
+ workflow_call:
+ workflow_dispatch:
+
+jobs:
+ unit-test:
+ name: Unit test Ansible ${{ matrix.ansible }} Py${{ matrix.python }}
+ runs-on: ubuntu-20.04
+ defaults:
+ run:
+ working-directory: ansible_collections/vultr/cloud
+ strategy:
+ fail-fast: false
+ matrix:
+ ansible:
+ - stable-2.14
+ python:
+ - "3.10"
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v3
+ with:
+ path: ansible_collections/vultr/cloud
+
+ - name: Set up Python ${{ matrix.python }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python }}
+
+ - name: Install ansible-base (${{ matrix.ansible }})
+ run: |
+ python -m pip install --upgrade pip
+ pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
+
+ - name: Build and install collection
+ run: |
+ ansible-galaxy collection build .
+ ansible-galaxy collection install *.gz
+
+ - name: Run the tests
+ run: >-
+ ansible-test
+ units
+ --docker
+ -v
+ --color
+ --python ${{ matrix.python }}
+ --coverage
+
+ - name: Generate coverage report
+ run: >-
+ ansible-test
+ coverage xml
+ -v
+ --requirements
+ --group-by command
+ --group-by version
+ - uses: codecov/codecov-action@v3
+ with:
+ fail_ci_if_error: false
diff --git a/ansible_collections/vultr/cloud/.gitignore b/ansible_collections/vultr/cloud/.gitignore
new file mode 100644
index 000000000..6c70190b5
--- /dev/null
+++ b/ansible_collections/vultr/cloud/.gitignore
@@ -0,0 +1,4 @@
+cloud-config-vultr.ini
+output
+resources
+vultr-cloud-*.tar.gz
diff --git a/ansible_collections/vultr/cloud/.yamllint b/ansible_collections/vultr/cloud/.yamllint
new file mode 100644
index 000000000..882767605
--- /dev/null
+++ b/ansible_collections/vultr/cloud/.yamllint
@@ -0,0 +1,33 @@
+---
+# Based on ansible-lint config
+extends: default
+
+rules:
+ braces:
+ max-spaces-inside: 1
+ level: error
+ brackets:
+ max-spaces-inside: 1
+ level: error
+ colons:
+ max-spaces-after: -1
+ level: error
+ commas:
+ max-spaces-after: -1
+ level: error
+ comments: disable
+ comments-indentation: disable
+ document-start: disable
+ empty-lines:
+ max: 3
+ level: error
+ hyphens:
+ level: error
+ indentation: disable
+ key-duplicates: enable
+ line-length: disable
+ new-line-at-end-of-file: disable
+ new-lines:
+ type: unix
+ trailing-spaces: disable
+ truthy: disable
diff --git a/ansible_collections/vultr/cloud/CHANGELOG.rst b/ansible_collections/vultr/cloud/CHANGELOG.rst
new file mode 100644
index 000000000..9374416d8
--- /dev/null
+++ b/ansible_collections/vultr/cloud/CHANGELOG.rst
@@ -0,0 +1,157 @@
+==============================
+Vultr Collection Release Notes
+==============================
+
+.. contents:: Topics
+
+
+v1.8.0
+======
+
+Minor Changes
+-------------
+
+- instance - Implemented a new ``state`` equal ``reinstalled`` to reinstall an existing instance (https://github.com/vultr/ansible-collection-vultr/pull/66).
+- inventory - Bare metal support has been implemented (https://github.com/vultr/ansible-collection-vultr/pull/63).
+
+v1.7.1
+======
+
+Bugfixes
+--------
+
+- instance - Fixed an issue when deleting an instance in locked state. (https://github.com/vultr/ansible-collection-vultr/pull/68)
+- inventory - Fixed the issue instance tags were not returned (https://github.com/vultr/ansible-collection-vultr/issues/69)
+
+v1.7.0
+======
+
+Minor Changes
+-------------
+
+- instance - Added argument ``snapshot`` to support creation of instances via snapshot (https://github.com/vultr/ansible-collection-vultr/pull/56).
+
+New Modules
+-----------
+
+- snapshot - Manages snapshots on Vultr
+- snapshot_info - Gather information about the Vultr snapshots
+
+v1.6.0
+======
+
+Minor Changes
+-------------
+
+- inventory - Added IPv6 support by adding ``v6_main_ip`` to the attributes and improved docs (https://github.com/vultr/ansible-collection-vultr/pull/54).
+
+v1.5.1
+======
+
+Bugfixes
+--------
+
+- instance - An error that caused the start script not to be processed has been fixed. (https://github.com/vultr/ansible-collection-vultr/issues/49)
+- instance_info - The problem that the module was missing in the runtime action group has been fixed.
+
+v1.5.0
+======
+
+Minor Changes
+-------------
+
+- instance - Implemented VPC support to attach/detach VPCs (https://github.com/vultr/ansible-collection-vultr/pull/46).
+
+New Modules
+-----------
+
+- instance_info - Get information about the Vultr instances
+
+v1.4.0
+======
+
+New Plugins
+-----------
+
+Inventory
+~~~~~~~~~
+
+- vultr - Retrieves list of instances via Vultr v2 API
+
+v1.3.1
+======
+
+Bugfixes
+--------
+
+- instance - Fixed an issue with ssh keys being ignored when deploying an new instance.
+
+v1.3.0
+======
+
+Bugfixes
+--------
+
+- instance - Fixed the handling for activating/deactivating backups.
+
+v1.2.0
+======
+
+Minor Changes
+-------------
+
+- block_storage - Added the parameter ``block_type`` to configure block types, default value is ``high_perf``.
+- dns_record - Removed the default value ``0`` for the optional parameter ``priority``.
+
+v1.1.0
+======
+
+Minor Changes
+-------------
+
+- block_storage - the default value for parameter ``live`` while attaching a volume changed to a more sensible default ``false``.
+
+New Modules
+-----------
+
+- instance - Manages server instances on Vultr.
+
+v1.0.1
+======
+
+Minor Changes
+-------------
+
+- Improved documentation and removed unused code.
+
+v1.0.0
+======
+
+New Modules
+-----------
+
+- account_info - Get information about the Vultr account.
+- block_storage - Manages block storage volumes on Vultr.
+- block_storage_info - Get information about the Vultr block storage available.
+- dns_domain - Manages DNS domains on Vultr.
+- dns_domain_info - Gather information about the Vultr DNS domains available.
+- dns_record - Manages DNS records on Vultr.
+- firewall_group - Manages firewall groups on Vultr.
+- firewall_group_info - Gather information about the Vultr firewall groups available.
+- firewall_rule - Manages firewall rules on Vultr.
+- firewall_rule_info - Gather information about the Vultr firewall rules available.
+- network - Manages networks on Vultr.
+- network_info - Gather information about the Vultr networks available.
+- os_info - Get information about the Vultr OSes available.
+- plan_info - Gather information about the Vultr plans available.
+- plan_metal_info - Gather information about the Vultr bare metal plans available.
+- region_info - Gather information about the Vultr regions available.
+- reserved_ip - Manages reserved IPs on Vultr.
+- ssh_key - Manages ssh keys on Vultr.
+- ssh_key_info - Get information about the Vultr SSH keys available.
+- startup_script - Manages startup scripts on Vultr.
+- startup_script_info - Gather information about the Vultr startup scripts available.
+- user - Manages users on Vultr.
+- user_info - Get information about the Vultr user available.
+- vpc - Manages VPCs on Vultr.
+- vpc_info - Gather information about the Vultr vpcs available.
diff --git a/ansible_collections/vultr/cloud/CONTRIBUTING.md b/ansible_collections/vultr/cloud/CONTRIBUTING.md
new file mode 100644
index 000000000..44683c135
--- /dev/null
+++ b/ansible_collections/vultr/cloud/CONTRIBUTING.md
@@ -0,0 +1,6 @@
+# Contributing
+
+Any contribution is welcome and we only ask contributors to:
+
+- Create an issues for any significant contribution that would change a large portion of the code base.
+- Provide at least integration tests for any contribution
diff --git a/ansible_collections/vultr/cloud/COPYING b/ansible_collections/vultr/cloud/COPYING
new file mode 100644
index 000000000..94a045322
--- /dev/null
+++ b/ansible_collections/vultr/cloud/COPYING
@@ -0,0 +1,621 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
diff --git a/ansible_collections/vultr/cloud/FILES.json b/ansible_collections/vultr/cloud/FILES.json
new file mode 100644
index 000000000..e4c120fb8
--- /dev/null
+++ b/ansible_collections/vultr/cloud/FILES.json
@@ -0,0 +1,2301 @@
+{
+ "files": [
+ {
+ "name": ".",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".ansible-lint",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8e858e68d7c1937d65dfcad8b39b28b8d7e41aac65eff967772fba0c3a882a15",
+ "format": 1
+ },
+ {
+ "name": "codecov.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0271dcfe609d71afb466112f2d1c4c13943580fa97bb42b2baa08a1c37bb1c14",
+ "format": 1
+ },
+ {
+ "name": "README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d0781fe71bb74c2b2aaef28dc2c5e081dd0f4b3977a1247c72b22827d5dc6726",
+ "format": 1
+ },
+ {
+ "name": "meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "meta/runtime.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "491775c582aeecf06f52f7ed2c3764ebe5e6c35476c8f02c9a4068745385ccac",
+ "format": 1
+ },
+ {
+ "name": "tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/cloud-config-vultr.ini.template",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "13818bbda928f18107c0e94118d0bd1f52fc805751aeba8f278140c7dc6e5e29",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "78b2bbacaa516217cf90de007da05136b7f08ef90bcb8c6d9e6320eaee45ee52",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b3a529e7fe7a88bd74d28e0d1a59444ff919861c898ce936304aa3cf905226",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "10b22387a8147bd98ea199fa7e8866837cb3742dd173a2bb2f1c4bfefb326741",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/common",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/common/default",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/common/default/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "11f87c1aa19551822d0b8585fcbb27151354e93cca5298e419581a349a23896d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/common/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e084a3683ef795d1cdbf5e9b253f2ca1f783ae0d0d6e47e419acbbc4fc80bbfa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "025d35e438e475b5cae504dcf1dcb8a425de2a5cbff0502018c99ad6780b2960",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/tasks/stop-start.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "217770633862454ea3c34efe13e29e29a8fb5cd297807c8dd49065f3beec39c3",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/tasks/failures.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b1180d83e69df042e848919bbd93967f6a316ffe983c2d7ad0838b26140d46f4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "98d1c97130c60cd0b5b7594edbf892f99b2d6a5ae73fd24d71e4effdfd415de6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/tasks/reinstall.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0cc5b6784d2d8030444d57d871f80b2f1a453132fccdeb002142eb027576ebbe",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/tasks/present.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "96e9c85025aa4aa2b6bd614718d698d0174563a27d7c9af1927428a40b31528d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/tasks/absent.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2d33951d4d498963a2311fea64fdf4a1a50b39ea9712ed72b4955393fc1a90c4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a30d3095617347fb25ffcada3fa1d94729d2e53f0149f1d3379d93270b7a4359",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "008e0933f58e74fd98a4b0600ff49d5ac7e862fe19439be701d180435472c87d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "158f45cabb1bb2f67511f1885c51b65872642bbcaa2915b8605d1f763ce1f832",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3a42de11dbbb07c09b93bfbb2d99d641f66dacb9aa96752234cb55db517f9e89",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/instance_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0284c806f32966951ab87baa051d3be2fe9a8839e37c55c760c695730db110cd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/tasks/failures.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bb2a0533a657d8ccdc7d750a4e6607648123016a127b9a8337c92bcfd4faf7dc",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7ce50b2181ffe6e2121e1692900fdb107636f90e048c195327fcc13737816a31",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/tasks/present.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "30c0334aed12e3f1d1d319de71c91e8faa7e90c0ba23ea8af12e7f66eb1dfb9f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/tasks/absent.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63b358651e57593af74d74bf7ab7e7812a77443ba1628f321830199245f55760",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6a784801be127bde96b005e775b8981f116875928902348ec6c9384de1b5097b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/plan_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/plan_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/plan_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "501533396ed8009dc79e310c95d764591704b6cd32091ee08eebd005f8a4b87b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/plan_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "20e5a94cc522ef7c6a387acaacce5c6d1a4127524fda45937a22b58e83a38c42",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d5738ca7eeca0a524a80197d73b1d677913903103d5bea0663c8fdc66eb6c09c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "81ba8e5671cf9d77b15558eb21489b807a60b071c19dc5a16cbfd9ba6ccfe835",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/region_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/region_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/region_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1e9238ef3b628e9be3f45f1907eb44d53a34f973b548064abff1f36d525a8bab",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/region_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "58728de0ce48a0024eeadf07e4b738b68aa1533ebdad396c9bf0bf0857475365",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "44ed0d376e3a684d03aca3056db7bd74b63451f5334639ae37970b4b468e900d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f09f3081e9a29164ed5d17114a52e97f2b8190d31c8c99cd23601d9f53c50e01",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1284e6369a45c85f50eb9267063e4f9bba78064dd1abb497a660e54eb9ad1e9a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b3a529e7fe7a88bd74d28e0d1a59444ff919861c898ce936304aa3cf905226",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "10b22387a8147bd98ea199fa7e8866837cb3742dd173a2bb2f1c4bfefb326741",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2c3ab8f42c86c9cc15d661adfc440632272d45408ce3bae07746b2756df93d6c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "87dc91ac04c12df5f20f7535d800a42a2e1336b2310b9371c2a59af44f078ce8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "51c5fca4c8d9360a6379827ab054a14a88137dbf75709539bf2deada8421a92f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/reserved_ip",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/reserved_ip/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/reserved_ip/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/reserved_ip/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/reserved_ip/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6a9fe617e2d8003cbe4538d2c1f45f27c75001c7687d17e511e3fe15186b94cf",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/reserved_ip/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ca173941bf646f76a6f8336f10b09a629e352bb355a51f62fb5c1440c55bb204",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/reserved_ip/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/reserved_ip/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e6c4fed7783e0ab2811bd7ca6dcbf1708485d91fca4ace1397150e79159bd327",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/reserved_ip/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7c2a325b079272307d33edbeaa4492a3facbc9c31bb071f32d9fc7bde9ddd567",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "72e3197710fa41991bd5beaeb212d73e3833ee807ae8d30c9d83fcf775180101",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6d0f6b5b87f1f2f2d734750fa026610f0ecccbca7d6c7ccedf1d394daa2c0787",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6f163960098273136e9b6baf9c853e6178c8c34329d584e0b33e41250cd19483",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b3a529e7fe7a88bd74d28e0d1a59444ff919861c898ce936304aa3cf905226",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ce7cb163662ec14873afee9b83c34874bd0eaf496890d7b7b35d488bf094461b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_group/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8352dbed6ddb1ceecbc7f46734bfe3db7d6dda7049f6ca13601847227e524fb0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "44ed0d376e3a684d03aca3056db7bd74b63451f5334639ae37970b4b468e900d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2db62c7b2e06217cc6a92ca02e997ef2a276460c45d37953bba64b9f2ec3078e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ssh_key/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4725bc0f78af0b6fafd93ae473fdace0c3baa28527e7b65e4e63c7d5bf5790ee",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "74b565de2124e4a53853a1dc2d79d3e765bd00578f25260427c52b082a0aebba",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7690ab5d3be0f969367e46923242bed255c52807b27c7ca97c492002e61e4056",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/tasks/update_record.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "69f1046400a3db0688ab921d4b1b707bf7fdf26ab133654d7e372627078b03c5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/tasks/record.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ac2ce46179ea10858a1a055df4fa27652e122ca7f0cc19b7494a3028b6894af9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b17ff013393d7b1d288a2d6fc4f2c4befddd5684e41544862fc11f4db00310c5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/tasks/test_fail_multiple.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "efc91209a8b8d5f616816c27ee3542c437695ad7902df49d110786a75381de9a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/tasks/create_record.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "45ab07fd1caf14b7427743b72e74713dcc13374067223908edfa83415c6d187e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/tasks/remove_record.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "40ab1dc2190120e706d7dd5a51dc8dd3ce8bc7c3f347f24fe985cc77ac310ff6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2461155c079932287a72670c97c3251a2821e8ab580d9ca305fa456b02cdff13",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1b5619716102d8ec920db97a6988787c780ee277398afe38af1edc7b0af68a6a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_record/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e48cbcad848aa1212a02ed6db988f09267d32b6195eed356882eed9f2e4dd39a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5caa8e411c0d84429e587e397e283e5c989c4ac2ef39965c255fbb5d18e1b3fa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e9a72a5ae88e71690565abf81fe1845976e98e4b60c6025f0679921da414ceac",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/plan_metal_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/plan_metal_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/plan_metal_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "30fa2cd68fb86755e1ba3ba2ef676feea82c54901bfaa77897364e2877d2d8af",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/plan_metal_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/account_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/account_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/account_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2b49a94c64afb9d4d95f3cacf9ea2667390dd014585eb65ff4d15e026e346e2e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/account_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a9f61a9487700a83508395d74ce06374baecfcaf4306b30f008d8b726c626a69",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/os_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/os_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/os_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ab3741f185714f47703a62373e1c60d4555a7cb0604b018ab681cab0bd63568a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/os_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6e9e3942703ae1ca3cfa4a8a3017fc54c0f627edc41fbcf143ea71e4c6782b72",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage/tasks/failures.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "70a2828cfc6a42aea15ca265c29c3b7c0489427f1e009ebc3e8668ce5dd505f1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "52660389f63f9f8b0b0faa24bdbbf8f28ce264f8fceb31a44e4bd0aca32a904d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage/tasks/tests_attach_to_server.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "de45063f8ce9cd2b9a7554cdcf7f1c9596f50cd1376ef69f3bd042481b321c9a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0015e74d8ad929993ebf0840e53120cf208ae9302ddbcb4c03bef85428cd8052",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/block_storage/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c759330d083de4c1388c2a495db6e58cb2e8de6ff80d3c54ee1982e020d4cb1a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5caa8e411c0d84429e587e397e283e5c989c4ac2ef39965c255fbb5d18e1b3fa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a554c895ee456e6b7a52b47944b6dde91718e705feae1b17240f11e709d65836",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/user/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "40df39c4e807905c239b84032700f2f8afef295404a81d33f456bb8d7d2de2db",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2461155c079932287a72670c97c3251a2821e8ab580d9ca305fa456b02cdff13",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "897005cc5012d5148cb547b674f0cdd1883702dd5bf7e06ce57e0df4937eee31",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/dns_domain/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot_info/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7e148c20a4f98ae35e0d5f4ae918dd4ace006c3522d2f4a28d60e502c1742212",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "00c1b19510489064de57f159c3cfae2ed964ad5064e770cff0849b5243cc417e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f7167834ffb188e37b48bf50ed7112fa6b3854c473f9a27d925f0ff059aa2686",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snapshot_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3414e6f7e40e8b97ec6fa43d1c10284fb9e2dc05c83fba44fb7eda26067efb87",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/tasks/rule_absent.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8406c5b815036b6bf808510a93d794bdf77d7ca493ae4af74b6d02d60ea873bf",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "754db3bbf45a9b97110c0523b140919d4540ebf1ab2d0191616f77955dde7ece",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/tasks/rule_present.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "52183ff79e735f2c90e8bf47e8bd2218b3fe12e0beb4755f1c328fc2addd062a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "99a6c0a603a706c1beeb8e0305729328dcee927b8dccabf55d2ca241752069a8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/firewall_rule/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c1e7a5d54828ea8746f35c153e693af2519b51ef74ef01a016cd7ef51b578f21",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d5738ca7eeca0a524a80197d73b1d677913903103d5bea0663c8fdc66eb6c09c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8825f1598fe036be8c0f7259ba05ad408acb9a9bf106da582a1e0f58040e1c40",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/startup_script/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc/tasks/tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7684abfe6f192643bfff3c6694ee6780e809801f899001a32b13c2757c374399",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "72e3197710fa41991bd5beaeb212d73e3833ee807ae8d30c9d83fcf775180101",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6d0f6b5b87f1f2f2d734750fa026610f0ecccbca7d6c7ccedf1d394daa2c0787",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vpc/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e6908b2c939974fe0c6636ebb5d908284145edfb8ae78ebf2ca6b73d15a398a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fad8168157b59ea211367da3adec3c025885b88e940a43fbdd8c5b9a8f06a791",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_snapshot.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c4b80c0623be8fc9b3715e96c370274a9544a722c081f2cd176964e403eb70e3",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_user.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d045ec23fee0ba28312d3a62b2c177e40e2991bafd1363f4862585f2cbdcfb5b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_reserved_ip.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7f55ef9910de1c95c3f152822b02b1dcc77bc347c559f4d0ea9850ed67ed0466",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_block_storage.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f1b0b7013c9ed7e03d27d7f213415654e0e57b204526029921416e1722dd8c82",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_vpc.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8cb8e6f9ea326d780e4565a67a967911fdf9ca09a039b904b600f4674955eb59",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_instance.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ac852429779c61e3db9dcb59dbf066ee2c5e169c54665da6a679c4b60397d2fd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_network.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1c6f111d899836a496e790770077aa92db40ceca90633a5d5b72200a388dce2e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_firewall_group.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c0c8fb99ae5f40480ba7b0da24f35632388c3865108d7d5148e87dace9adc816",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_startup_script.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d3f428f0cdeb1bf14cac364c19580a61a845672a552d293c96b23e8f860764f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_dns_domain.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0f70151df2fe2eb1b434fccf8e2d8eba7e13db7cb110520c1e69784499bdc2a8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/tasks/cleanup_ssh_key.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "26d0dc382638376f115608d46bba80b2dd36ec96d9d290115c931051532d3f76",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b9f3ec8b4e4bf39dc1301f7187db3d08097bedf77f3364c79f2044ffd5db9d12",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cleanup/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e084a3683ef795d1cdbf5e9b253f2ca1f783ae0d0d6e47e419acbbc4fc80bbfa",
+ "format": 1
+ },
+ {
+ "name": "tests/unit",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory/test_vultr.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9b938dddb400485de14daa3ea2d59d0ec96e5f8e129806e09bccf75a7af4db4d",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory/fixtures",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory/fixtures/empty_vultr_inventory.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "64191612bc4b0099f55554c92444f8f71ac651b38875433e4a2a351ebb86fc1a",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory/fixtures/vultr_inventory.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7966a533c5dbbe1df5eddac1ec56df52ec808b6a39303a51467dfcb74c329cc0",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory/fixtures/vultr_inventory_page1.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "004b664e8ddebb2714c97f7ef2c95be8d7b2e770089eb49b563fb321e4a79823",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory/fixtures/vultr_inventory_page2.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b1151ecdeb91d94258df245931619c94dfdbee87308e8f126cef86932ea54436",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory/fixtures/unauthorized_vultr_inventory.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "505876bcb387732db0065e9ff092c3060c8436dbe15e7ec98846899cf81603f4",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "05a68f8431655d8f086d2c5b8e93ef5b2a124ff2dfa5e8f44f647f404af16627",
+ "format": 1
+ },
+ {
+ "name": ".yamllint",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5845e18e9f23155f423207df9abac970aed687c638620bc2c9ee06706191054b",
+ "format": 1
+ },
+ {
+ "name": ".gitignore",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1467ad38919911ec5759af24376728faf2361c0335d52fb8bea4853e7b698b48",
+ "format": 1
+ },
+ {
+ "name": "CONTRIBUTING.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d61725d614410e2ee0a900fb0f6b6d742ad8fb689ae27c4d6a3a7f89e82fc791",
+ "format": 1
+ },
+ {
+ "name": "plugins",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/modules",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/region_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ee6e31f3192bbe6e0db69cd7efef79a3a3fee40763071aa5c674f5c6951d7bdb",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/startup_script.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "14be407f3eb256735311fde075a3c983abb9b6932925d412e5782cec26c3e23f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/user.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "38d3651f9b624fe512dae40c4ef24e4ccb0eae4ea9c394d260b851ff57dc8365",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/dns_domain_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f76e554deed6163146c291612e807058309f4553b8d5ff9798a0fabe27717307",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/os_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0143ad73c6b10692c6577730523b0159782bb6a678d3946dc920b3b758565155",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/account_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "234df324cb37004dff1e9d5847998f97304c9228e67815f05b5087ab5709e911",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/block_storage_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d2677e90317fc892df48133c755f1c9cf8e1281d610f43937abc54e79f78ee81",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/plan_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3648af6b8fd69f3bb66faf265767fd39a7afd5bebd5f88964db42dc6d0d8d392",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/firewall_rule.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1b95d2b2c729517b79ce3e06d988defa8803b75060b736279eeeec8ae0d815e0",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/snapshot_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a60ecc36574d60168903ee239185d42e636c8d26356bb84d6c666d8ab7368e50",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/user_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ae4e7899a1107f0d9a2dbfac410209528d687ceef6c9f587b3d78cdb974d8e7f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/instance.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c6c7aa932359fcc9711e838739cc1a4f22c628428f115801d8212cf9524dfc3f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/plan_metal_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "93bda0d2911f927951c30540a54a8da71a61a20c7f9cafc7368097d335c47aa5",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/startup_script_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "23134fcb25c56ab61a08afe195100cd4f2eb5ef14b1a8ba6bfc7b82cdea57859",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/firewall_group.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7e5482639e8b600dff912fc03f7b0baa24a3cfa70f807eeeeb6c1ebfcf354f94",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/dns_record.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4b29de118b42237350431b7bef3dbf92ff98bfe989183756aea92efb0b73589d",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/instance_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c29fdb4fab431c06ec8eba206ce48df96c5d39c2bff0f9ca632133993bd78891",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/__init__.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/block_storage.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d2a98391d3d84671552b48b0fad61811f753420f09b5b94626e511b3c74cf93f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vpc_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "903efd1d0f822de7aaaf659d968e13e9104d6af4c3667a782efd8bf056662829",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/dns_domain.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "de781d3439aba96749c83b24b29c15e1f62ac807c8cc793e08ea374ece4c3c68",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/firewall_rule_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "267c9f763168ce7b6c938e874b4048d6492add6766406d3a6cbc3d227ed14da3",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vpc.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9ea848792c5ac44d5d25f366dbab63916f6797c977238ede08a2b2e08f74933b",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/ssh_key.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5e1a8e741f196a6b080077b88aa14ec6595878108978ef230224592b161ca44b",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/firewall_group_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2e4dce46bd2ddbbd7ded11f11f8d4b57f15f603595f69d142e1c10bc8532e936",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/snapshot.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "361a3cdac8de6b7ff2ba98859389d9d53e6a45b5f003bd069d9ea78a2759bcfc",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/reserved_ip.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a28bb0cafda10d630df72411835c4eb01c763888c9222bc81ffe37a46a281dfe",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/ssh_key_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5cedb298db9d7b8b3888eed9a734309a5ef0b0cae1052211cc0a571a9c2ada22",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/vultr_v2.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e49032c648151d4eeaaf522522afe8955a1ab734c8742cc82fe7111b4a7166b8",
+ "format": 1
+ },
+ {
+ "name": "plugins/inventory",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/inventory/vultr.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3f27d32a30a548dffa6c2e327ba4db98db9c4ac40d6682a3af677e5dc810d882",
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments/__init__.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments/vultr_v2.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "64f7eb39cbe633e26394afeb6d125d440046ec37f1cf82d4a4ea072092954afa",
+ "format": 1
+ },
+ {
+ "name": "changelogs",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "changelogs/.gitignore",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "919ef00776e7d2ff349950ac4b806132aa9faf006e214d5285de54533e443b33",
+ "format": 1
+ },
+ {
+ "name": "changelogs/changelog.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6feaa7b0a10c92895065283614f9f6a39d59fd2ca304389535252396233094d1",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/.keep",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "changelogs/config.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0d1c790424791b634a9c7704aa0e9ec56e3ff34a602f269d68a356d87c777b3a",
+ "format": 1
+ },
+ {
+ "name": ".github",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".github/dependabot.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d207e80d10726360f2046d4b2473a3cfd9f9eca99590281fa39d88f78e745145",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/integration.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ba0c3bd03b358fd8cabaeb9fa2fe824530564df5c529de700fce29f607056102",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/unit.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7051532c9f19b38b2ac988bfd7c937d5cdf7daa6b93aa120161216505c1d0b62",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/publish.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9efbf024e8a8ce47dd5e91f825c0ce533a67fb9c8155851df4676184d6f4d06d",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/sanity.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dc5cc7a6c0cea7cd93788a4db2cdfae337f39f98eca906cec9321b26209f9667",
+ "format": 1
+ },
+ {
+ "name": "COPYING",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c61f12da7cdad526bdcbed47a4c0a603e60dbbfdaf8b66933cd088e9132c303f",
+ "format": 1
+ }
+ ],
+ "format": 1
+} \ No newline at end of file
diff --git a/ansible_collections/vultr/cloud/MANIFEST.json b/ansible_collections/vultr/cloud/MANIFEST.json
new file mode 100644
index 000000000..787b93878
--- /dev/null
+++ b/ansible_collections/vultr/cloud/MANIFEST.json
@@ -0,0 +1,33 @@
+{
+ "collection_info": {
+ "namespace": "vultr",
+ "name": "cloud",
+ "version": "1.8.0",
+ "authors": [
+ "Ren\u00e9 Moser (@resmo)",
+ "Yanis Guenane (@Spredzy)",
+ "jasites (@jasites)"
+ ],
+ "readme": "README.md",
+ "tags": [
+ "cloud",
+ "vultr"
+ ],
+ "description": "Ansible Collection for Vultr Cloud",
+ "license": [],
+ "license_file": "COPYING",
+ "dependencies": {},
+ "repository": "https://github.com/vultr/ansible-collection-vultr",
+ "documentation": "https://docs.ansible.com/ansible/latest/collections/vultr/cloud/",
+ "homepage": "https://github.com/vultr/ansible-collection-vultr",
+ "issues": "https://github.com/vultr/ansible-collection-vultr/issues"
+ },
+ "file_manifest_file": {
+ "name": "FILES.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1abc635ad92d54847dd169705eaa4f000ddd045fe65318c39625c860a273c69b",
+ "format": 1
+ },
+ "format": 1
+} \ No newline at end of file
diff --git a/ansible_collections/vultr/cloud/README.md b/ansible_collections/vultr/cloud/README.md
new file mode 100644
index 000000000..38880f9b6
--- /dev/null
+++ b/ansible_collections/vultr/cloud/README.md
@@ -0,0 +1,120 @@
+[![Collection integration](https://github.com/vultr/ansible-collection-vultr/actions/workflows/integration.yml/badge.svg?branch=main)](https://github.com/vultr/ansible-collection-vultr/actions/workflows/integration.yml) [![Codecov](https://img.shields.io/codecov/c/github/vultr/ansible-collection-vultr)](https://codecov.io/gh/vultr/ansible-collection-vultr) [![License](https://img.shields.io/badge/license-GPL%20v3.0-brightgreen.svg)](LICENSE)
+
+# Ansible Collection for Vultr Cloud
+
+This repository contains the `vultr.cloud` Ansible Collection . The collection will be part of the Ansible package and provides a series of Ansible modules and plugins for interacting with the [Vultr](https://www.vultr.com) Cloud. You can find the documentation for this collection on the [Ansible docs site](https://docs.ansible.com/ansible/latest/collections/vultr/cloud/).
+
+---
+**NOTE**
+
+`vultr.cloud` is the successor of exisitng `ngine_io.vultr` collection ([Ansible docs site](https://docs.ansible.com/ansible/latest/collections/ngine_io/vultr/)), which uses the deprecated Vultr v1 API.
+
+---
+
+## Ansible Version Compatibility
+
+Tested with Ansible Core versions >= 2.11.
+
+## Release Notes
+
+Release notes are available in our [changelog](https://github.com/vultr/ansible-collection-vultr/blob/main/CHANGELOG.rst).
+
+## Using this Collection
+
+This collection will be shipped with the Ansible package >=6.0.0. If you have it installed, no more action is required.
+
+If you have a minimal installation (only Ansible Core installed) or you want to use the latest version of the collection along with the whole Ansible package, you need to install the collection from [Ansible Galaxy](https://galaxy.ansible.com/vultr/cloud) manually with the `ansible-galaxy` command-line tool:
+
+ ansible-galaxy collection install vultr.cloud
+
+You can also include it in a `requirements.yml` file and install it via `ansible-galaxy collection install -r requirements.yml` using the format:
+
+```yaml
+collections:
+ - name: vultr.cloud
+```
+
+Note that if you install the collection manually, it will not be upgraded automatically when you upgrade the Ansible package. To upgrade the collection to the latest available version, run the following command:
+
+```bash
+ansible-galaxy collection install vultr.cloud --upgrade
+```
+
+You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax where `X.Y.Z` can be any [available version](https://galaxy.ansible.com/vultr/cloud):
+
+```bash
+ansible-galaxy collection install vultr.cloud:==X.Y.Z
+```
+
+See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
+
+## Contributing
+
+There are many ways in which you can participate in the project, for example:
+
+- Submit bugs and feature requests, and help us verify as they are checked in
+- Review source code changes
+- Review the documentation and make pull requests for anything from typos to new content
+- If you are interested in fixing issues and contributing directly to the code base, please see the [CONTRIBUTING](CONTRIBUTING.md) document.
+
+
+## Run Tests
+
+See [Testing collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections_testing.html) to learn how to test a collection.
+
+### Clone the Source
+
+```
+git clone git@github.com:vultr/ansible-collection-vultr.git
+cd ansible-collection-vultr
+```
+
+### Create a Virtual Environent
+
+```
+python3 -m venv .venv
+source .venv/bin/activate
+```
+
+### Install Ansible
+
+```bash
+pip install ansible
+```
+
+### Setup your Vultr API Key
+
+```bash
+cp tests/integration/cloud-config-vultr.ini.origin tests/integration/cloud-config-vultr.ini
+edit tests/integration/cloud-config-vultr.ini
+```
+
+### Runs Tests in Docker
+
+All vultr tests:
+
+```bash
+ansible-test integration --docker --diff -v cloud/vultr/
+```
+
+Specific vultr test e.g. ssh_key_info:
+
+```bash
+ansible-test integration --docker --diff -v cloud/vultr/ssh_key_info
+```
+
+## Releasing
+
+See the [Releasing Guidelines](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_releasing.html#releasing) to learn how to release this collection.
+
+## Code of Conduct
+
+We follow the Ansible Code of Conduct in all our interactions within this project.
+
+If you encounter abusive behavior violating the Ansible Code of Conduct, please refer to the policy violations section of the Code of Conduct for information on how to raise a complaint.
+
+## License
+
+GNU General Public License v3.0
+
+See [COPYING](COPYING) to see the full text.
diff --git a/ansible_collections/vultr/cloud/changelogs/.gitignore b/ansible_collections/vultr/cloud/changelogs/.gitignore
new file mode 100644
index 000000000..6be6b5331
--- /dev/null
+++ b/ansible_collections/vultr/cloud/changelogs/.gitignore
@@ -0,0 +1 @@
+/.plugin-cache.yaml
diff --git a/ansible_collections/vultr/cloud/changelogs/changelog.yaml b/ansible_collections/vultr/cloud/changelogs/changelog.yaml
new file mode 100644
index 000000000..a24c768f9
--- /dev/null
+++ b/ansible_collections/vultr/cloud/changelogs/changelog.yaml
@@ -0,0 +1,198 @@
+ancestor: null
+releases:
+ 1.0.0:
+ modules:
+ - description: Manages firewall rules on Vultr.
+ name: firewall_rule
+ namespace: ''
+ - description: Gather information about the Vultr firewall rules available.
+ name: firewall_rule_info
+ namespace: ''
+ - description: Manages VPCs on Vultr.
+ name: vpc
+ namespace: ''
+ - description: Gather information about the Vultr vpcs available.
+ name: vpc_info
+ namespace: ''
+ release_date: '2022-05-26'
+ 1.0.0-rc.1:
+ modules:
+ - description: Get information about the Vultr account.
+ name: account_info
+ namespace: ''
+ - description: Manages block storage volumes on Vultr.
+ name: block_storage
+ namespace: ''
+ - description: Get information about the Vultr block storage available.
+ name: block_storage_info
+ namespace: ''
+ - description: Manages DNS domains on Vultr.
+ name: dns_domain
+ namespace: ''
+ - description: Gather information about the Vultr DNS domains available.
+ name: dns_domain_info
+ namespace: ''
+ - description: Manages DNS records on Vultr.
+ name: dns_record
+ namespace: ''
+ - description: Manages firewall groups on Vultr.
+ name: firewall_group
+ namespace: ''
+ - description: Gather information about the Vultr firewall groups available.
+ name: firewall_group_info
+ namespace: ''
+ - description: Manages networks on Vultr.
+ name: network
+ namespace: ''
+ - description: Gather information about the Vultr networks available.
+ name: network_info
+ namespace: ''
+ - description: Get information about the Vultr OSes available.
+ name: os_info
+ namespace: ''
+ - description: Gather information about the Vultr plans available.
+ name: plan_info
+ namespace: ''
+ - description: Gather information about the Vultr bare metal plans available.
+ name: plan_metal_info
+ namespace: ''
+ - description: Gather information about the Vultr regions available.
+ name: region_info
+ namespace: ''
+ - description: Manages reserved IPs on Vultr.
+ name: reserved_ip
+ namespace: ''
+ - description: Manages ssh keys on Vultr.
+ name: ssh_key
+ namespace: ''
+ - description: Get information about the Vultr SSH keys available.
+ name: ssh_key_info
+ namespace: ''
+ - description: Manages startup scripts on Vultr.
+ name: startup_script
+ namespace: ''
+ - description: Gather information about the Vultr startup scripts available.
+ name: startup_script_info
+ namespace: ''
+ - description: Manages users on Vultr.
+ name: user
+ namespace: ''
+ - description: Get information about the Vultr user available.
+ name: user_info
+ namespace: ''
+ release_date: '2022-04-22'
+ 1.0.1:
+ changes:
+ minor_changes:
+ - Improved documentation and removed unused code.
+ fragments:
+ - summary.yaml
+ release_date: '2022-09-05'
+ 1.1.0:
+ changes:
+ minor_changes:
+ - block_storage - the default value for parameter ``live`` while attaching a
+ volume changed to a more sensible default ``false``.
+ fragments:
+ - block_storage-live.yml
+ modules:
+ - description: Manages server instances on Vultr.
+ name: instance
+ namespace: ''
+ release_date: '2022-09-09'
+ 1.2.0:
+ changes:
+ minor_changes:
+ - block_storage - Added the parameter ``block_type`` to configure block types,
+ default value is ``high_perf``.
+ - dns_record - Removed the default value ``0`` for the optional parameter ``priority``.
+ fragments:
+ - block_type_block_storage.yml
+ - dns_record_prio.yml
+ release_date: '2022-10-14'
+ 1.3.0:
+ changes:
+ bugfixes:
+ - instance - Fixed the handling for activating/deactivating backups.
+ fragments:
+ - instance-feature-handling.yml
+ release_date: '2022-10-28'
+ 1.3.1:
+ changes:
+ bugfixes:
+ - instance - Fixed an issue with ssh keys being ignored when deploying an new
+ instance.
+ fragments:
+ - instance-ssh-key.yml
+ release_date: '2022-11-14'
+ 1.4.0:
+ plugins:
+ inventory:
+ - description: Retrieves list of instances via Vultr v2 API
+ name: vultr
+ namespace: null
+ release_date: '2022-12-08'
+ 1.5.0:
+ changes:
+ minor_changes:
+ - instance - Implemented VPC support to attach/detach VPCs (https://github.com/vultr/ansible-collection-vultr/pull/46).
+ fragments:
+ - instance-vpcs.yml
+ modules:
+ - description: Get information about the Vultr instances
+ name: instance_info
+ namespace: ''
+ release_date: '2022-12-16'
+ 1.5.1:
+ changes:
+ bugfixes:
+ - instance - An error that caused the start script not to be processed has been
+ fixed. (https://github.com/vultr/ansible-collection-vultr/issues/49)
+ - instance_info - The problem that the module was missing in the runtime action
+ group has been fixed.
+ fragments:
+ - instance-script-id.yml
+ - instance_info-runtime.yml
+ release_date: '2022-12-30'
+ 1.6.0:
+ changes:
+ minor_changes:
+ - inventory - Added IPv6 support by adding ``v6_main_ip`` to the attributes
+ and improved docs (https://github.com/vultr/ansible-collection-vultr/pull/54).
+ fragments:
+ - inventory-ipv6.yml
+ release_date: '2023-01-15'
+ 1.7.0:
+ changes:
+ minor_changes:
+ - instance - Added argument ``snapshot`` to support creation of instances via
+ snapshot (https://github.com/vultr/ansible-collection-vultr/pull/56).
+ fragments:
+ - 56-instance_snapshot.yml
+ modules:
+ - description: Manages snapshots on Vultr
+ name: snapshot
+ namespace: ''
+ - description: Gather information about the Vultr snapshots
+ name: snapshot_info
+ namespace: ''
+ release_date: '2023-01-22'
+ 1.7.1:
+ changes:
+ bugfixes:
+ - instance - Fixed an issue when deleting an instance in locked state. (https://github.com/vultr/ansible-collection-vultr/pull/68)
+ - inventory - Fixed the issue instance tags were not returned (https://github.com/vultr/ansible-collection-vultr/issues/69)
+ fragments:
+ - 68-instance-locked-absent.yml
+ - 70-inventory-fix-tags-not-returned.yml
+ release_date: '2023-05-03'
+ 1.8.0:
+ changes:
+ minor_changes:
+ - instance - Implemented a new ``state`` equal ``reinstalled`` to reinstall
+ an existing instance (https://github.com/vultr/ansible-collection-vultr/pull/66).
+ - inventory - Bare metal support has been implemented (https://github.com/vultr/ansible-collection-vultr/pull/63).
+ fragments:
+ - 63-inventory-bare-metal.yml
+ - instance-reinstall.yml
+ release_date: '2023-05-21'
diff --git a/ansible_collections/vultr/cloud/changelogs/config.yaml b/ansible_collections/vultr/cloud/changelogs/config.yaml
new file mode 100644
index 000000000..56b733b58
--- /dev/null
+++ b/ansible_collections/vultr/cloud/changelogs/config.yaml
@@ -0,0 +1,29 @@
+changelog_filename_template: ../CHANGELOG.rst
+changelog_filename_version_depth: 0
+changes_file: changelog.yaml
+changes_format: combined
+keep_fragments: false
+mention_ancestor: true
+flatmap: true
+new_plugins_after_name: removed_features
+notesdir: fragments
+prelude_section_name: release_summary
+prelude_section_title: Release Summary
+sections:
+ - - major_changes
+ - Major Changes
+ - - minor_changes
+ - Minor Changes
+ - - breaking_changes
+ - Breaking Changes / Porting Guide
+ - - deprecated_features
+ - Deprecated Features
+ - - removed_features
+ - Removed Features (previously deprecated)
+ - - security_fixes
+ - Security Fixes
+ - - bugfixes
+ - Bugfixes
+ - - known_issues
+ - Known Issues
+title: Vultr Collection
diff --git a/ansible_collections/vultr/cloud/changelogs/fragments/.keep b/ansible_collections/vultr/cloud/changelogs/fragments/.keep
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/vultr/cloud/changelogs/fragments/.keep
diff --git a/ansible_collections/vultr/cloud/codecov.yml b/ansible_collections/vultr/cloud/codecov.yml
new file mode 100644
index 000000000..33c8f6eee
--- /dev/null
+++ b/ansible_collections/vultr/cloud/codecov.yml
@@ -0,0 +1,5 @@
+---
+coverage:
+ precision: 2
+ round: down
+ range: "70...100"
diff --git a/ansible_collections/vultr/cloud/meta/runtime.yml b/ansible_collections/vultr/cloud/meta/runtime.yml
new file mode 100644
index 000000000..7be048948
--- /dev/null
+++ b/ansible_collections/vultr/cloud/meta/runtime.yml
@@ -0,0 +1,29 @@
+---
+requires_ansible: ">=2.11"
+action_groups:
+ vultr:
+ - account_info
+ - block_storage
+ - block_storage_info
+ - dns_domain
+ - dns_domain_info
+ - dns_record
+ - firewall_group
+ - firewall_group_info
+ - firewall_rule
+ - firewall_rule_info
+ - instance
+ - instance_info
+ - os_info
+ - plan_info
+ - plan_metal_info
+ - region_info
+ - reserved_ip
+ - ssh_key
+ - ssh_key_info
+ - startup_script
+ - startup_script_info
+ - user
+ - user_info
+ - vpc
+ - vpc_info
diff --git a/ansible_collections/vultr/cloud/plugins/doc_fragments/__init__.py b/ansible_collections/vultr/cloud/plugins/doc_fragments/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/doc_fragments/__init__.py
diff --git a/ansible_collections/vultr/cloud/plugins/doc_fragments/vultr_v2.py b/ansible_collections/vultr/cloud/plugins/doc_fragments/vultr_v2.py
new file mode 100644
index 000000000..692103e8c
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/doc_fragments/vultr_v2.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2021 René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+
+ DOCUMENTATION = """
+options:
+ api_key:
+ description:
+ - API key of the Vultr API.
+ - Fallback environment variable C(VULTR_API_KEY).
+ type: str
+ required: true
+ api_timeout:
+ description:
+ - HTTP timeout to Vultr API.
+ - Fallback environment variable C(VULTR_API_TIMEOUT).
+ type: int
+ default: 180
+ api_retries:
+ description:
+ - Amount of retries in case of the Vultr API retuns an HTTP 503 code.
+ - Fallback environment variable C(VULTR_API_RETRIES).
+ type: int
+ default: 5
+ api_retry_max_delay:
+ description:
+ - Retry backoff delay in seconds is exponential up to this max. value, in seconds.
+ - Fallback environment variable C(VULTR_API_RETRY_MAX_DELAY).
+ type: int
+ default: 12
+ api_endpoint:
+ description:
+ - URL to API endpint (without trailing slash).
+ - Fallback environment variable C(VULTR_API_ENDPOINT).
+ type: str
+ default: https://api.vultr.com/v2
+ validate_certs:
+ description:
+ - Validate SSL certs of the Vultr API.
+ type: bool
+ default: true
+notes:
+ - Also see the API documentation on U(https://www.vultr.com/api/).
+"""
diff --git a/ansible_collections/vultr/cloud/plugins/inventory/vultr.py b/ansible_collections/vultr/cloud/plugins/inventory/vultr.py
new file mode 100644
index 000000000..c08446134
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/inventory/vultr.py
@@ -0,0 +1,348 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) jasites <jsites@vultr.com>
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# flake8: noqa: E402
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+name: vultr
+short_description: Retrieves list of instances via Vultr v2 API
+description:
+ - Vultr inventory plugin.
+ - Retrieves list of instances via Vultr v2 API.
+ - Configuration of this plugin is done with files ending with '(vultr|vultr_hosts|vultr_instances).(yaml|yml)'
+version_added: '1.4.0'
+author:
+ - jasites (@jasites)
+extends_documentation_fragment:
+ - constructed
+ - inventory_cache
+options:
+ api_endpoint:
+ description:
+ - URL to API endpint (without trailing slash).
+ - Fallback environment variable C(VULTR_API_ENDPOINT).
+ type: str
+ env:
+ - name: VULTR_API_ENDPOINT
+ default: https://api.vultr.com/v2
+ api_key:
+ description:
+ - API key of the Vultr API.
+ - Fallback environment variable C(VULTR_API_KEY).
+ type: str
+ env:
+ - name: VULTR_API_KEY
+ required: true
+ api_results_per_page:
+ description:
+ - When receiving large numbers of instances, specify how many instances should be returned per call to API.
+ - This does not determine how many results are returned; all instances are returned according to other filters.
+ - Vultr API maximum is 500.
+ - Fallback environment variable C(VULTR_API_RESULTS_PER_PAGE).
+ type: int
+ env:
+ - name: VULTR_API_RESULTS_PER_PAGE
+ default: 100
+ api_timeout:
+ description:
+ - HTTP timeout to Vultr API.
+ - Fallback environment variable C(VULTR_API_TIMEOUT).
+ type: int
+ env:
+ - name: VULTR_API_TIMEOUT
+ default: 60
+ attributes:
+ description:
+ - Instance attributes to add as host variables to each host added to inventory.
+ - See U(https://www.vultr.com/api/#operation/list-instances) for valid values.
+ type: list
+ elements: str
+ default:
+ - id
+ - region
+ - label
+ - plan
+ - hostname
+ - main_ip
+ - v6_main_ip
+ - tags
+ filters:
+ description:
+ - Filter hosts with Jinja2 templates.
+ - If not provided, all hosts are added to inventory.
+ type: list
+ elements: str
+ default: []
+ instance_type:
+ description:
+ - Type of instance.
+ type: str
+ default: cloud
+ choices:
+ - cloud
+ - bare_metal
+ version_added: '1.8.0'
+ plugin:
+ description:
+ - Name of Vultr inventory plugin.
+ - This should always be C(vultr.cloud.vultr).
+ type: str
+ choices: ['vultr.cloud.vultr']
+ required: true
+ variable_prefix:
+ description:
+ - Prefix of generated variables (e.g. C(id) becomes C(vultr_id)).
+ type: str
+ default: 'vultr_'
+ validate_certs:
+ description:
+ - Validate SSL certs of the Vultr API.
+ type: bool
+ default: true
+notes:
+ - Also see the API documentation on U(https://www.vultr.com/api/).
+"""
+
+EXAMPLES = """
+---
+# File endings vultr{,-{hosts,instances}}.y{,a}ml
+# All configuration done via environment variables:
+plugin: vultr.cloud.vultr
+
+# Grouping and filtering configuration in inventory file
+plugin: vultr.cloud.vultr
+api_key: '{{ lookup("pipe"), "./get_vultr_api_key.sh" }}'
+keyed_groups:
+ - key: vultr_tags | lower
+ prefix: ''
+ separator: ''
+filters:
+ - '"vpc" in vultr_tags'
+ - 'vultr_plan == "vc2-2c-4gb"'
+
+# Unless you can connect to your servers via it's vultr label,
+# we suggest setting ansible_host with compose:
+plugin: vultr.cloud.vultr
+compose:
+ ansible_host: vultr_main_ip
+
+# Respectively for IPv6:
+plugin: vultr.cloud.vultr
+compose:
+ ansible_host: vultr_v6_main_ip
+
+# Prioritize IPv6 over IPv4 if available.
+plugin: vultr.cloud.vultr
+compose:
+ ansible_host: vultr_v6_main_ip or vultr_main_ip
+
+# Querying the bare metal instances
+plugin: vultr.cloud.vultr
+instance_type: bare_metal
+"""
+
+RETURN = r""" # """
+
+import json
+
+from ansible.errors import AnsibleError, AnsibleParserError
+from ansible.module_utils._text import to_native
+from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError
+from ansible.module_utils.urls import Request
+from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, Constructable
+
+from ..module_utils.vultr_v2 import VULTR_USER_AGENT
+
+
+class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
+
+ NAME = "vultr.cloud.vultr"
+
+ RESOURCES_PER_TYPE = {
+ "cloud": {
+ "resource": "instances",
+ "response": "instances",
+ },
+ "bare_metal": {
+ "resource": "bare-metals",
+ "response": "bare_metals",
+ },
+ }
+
+ def _get_instances(self):
+ instances = []
+ api_key = self.get_option("api_key")
+ if self.templar.is_template(api_key):
+ api_key = self.templar.template(api_key)
+
+ headers = {
+ "Content-Type": "application/json",
+ "User-Agent": VULTR_USER_AGENT,
+ "Authorization": "Bearer {0}".format(api_key),
+ }
+
+ self.req = Request(
+ headers=headers,
+ timeout=int(self.get_option("api_timeout")), # type: ignore
+ validate_certs=self.get_option("validate_certs"), # type: ignore
+ )
+
+ instance_type_config = self.get_option("instance_type") or "cloud"
+ self.display.vvv("Type is: {0}".format(instance_type_config))
+
+ instance_type = self.RESOURCES_PER_TYPE[instance_type_config]
+
+ api_endpoint = "{0}/{1}?per_page={2}".format(
+ self.get_option("api_endpoint"),
+ instance_type["resource"], # type: ignore
+ self.get_option("api_results_per_page"),
+ )
+
+ cursor = ""
+ req_url = api_endpoint
+ try:
+ while True:
+ self.display.vvv("Querying API: {0}".format(req_url))
+
+ page = json.load(self.req.get(req_url))
+ instances.extend(page[instance_type["response"]]) # type: ignore
+ cursor = page["meta"]["links"]["next"]
+
+ if cursor == "":
+ return instances
+
+ req_url = "{0}&cursor={1}".format(api_endpoint, cursor)
+
+ except (KeyError, ValueError):
+ raise AnsibleParserError("Unable to parse JSON response.")
+ except (URLError, HTTPError) as err:
+ raise AnsibleParserError(err)
+
+ def _populate(self, instances):
+ attributes = self.get_option("attributes")
+ host_filters = self.get_option("filters")
+ strict = self.get_option("strict")
+ variable_prefix = self.get_option("variable_prefix")
+
+ for instance in instances:
+ instance_label = instance.get("label")
+
+ if not instance_label:
+ self.display.warning(msg="instance ID {0} has no label, skipping.".format(instance.get("id")))
+ continue
+
+ host_variables = {}
+ for k, v in instance.items():
+ if k in attributes:
+ host_variables["{0}{1}".format(variable_prefix, k)] = v
+
+ if not self._passes_filters(
+ host_filters,
+ host_variables,
+ instance_label,
+ strict, # type: ignore
+ ):
+ self.display.vvv("Host {0} excluded by filters".format(instance_label))
+ continue
+
+ self.inventory.add_host(instance_label) # type: ignore
+
+ for var_name, var_val in host_variables.items():
+ self.inventory.set_variable(instance_label, var_name, var_val) # type: ignore
+
+ self._set_composite_vars(
+ self.get_option("compose"),
+ self.inventory.get_host(instance_label).get_vars(), # type: ignore
+ instance_label,
+ strict, # type: ignore
+ )
+
+ self._add_host_to_composed_groups(
+ self.get_option("groups"),
+ dict(),
+ instance_label,
+ strict, # type: ignore
+ )
+
+ self._add_host_to_keyed_groups(
+ self.get_option("keyed_groups"),
+ dict(),
+ instance_label,
+ strict, # type: ignore
+ )
+
+ def _passes_filters(self, filters, variables, host, strict=False):
+ if filters and isinstance(filters, list):
+ for template in filters:
+ try:
+ if not self._compose(template, variables):
+ return False
+ except Exception as e:
+ if strict:
+ raise AnsibleError(
+ "Could not evaluate host filter {0} for {1}: {2}".format(
+ template,
+ host,
+ to_native(e),
+ ),
+ )
+ return False
+ return True
+
+ def verify_file(self, path):
+ valid = False
+ if super(InventoryModule, self).verify_file(path):
+ if path.endswith(
+ (
+ "vultr.yaml",
+ "vultr.yml",
+ "vultr_hosts.yaml",
+ "vultr_hosts.yml",
+ "vultr_instances.yaml",
+ "vultr_instances.yml",
+ )
+ ):
+ valid = True
+ else:
+ self.display.vvv(
+ "Skipping due to inventory configuration file name mismatch. "
+ "Valid filename endings: "
+ "vultr.yaml, vultr.yml, vultr_hosts.yaml, vultr_hosts.yml, "
+ "vultr_instances.yaml, vultr_instances.yml"
+ )
+ return valid
+
+ def parse(self, inventory, loader, path, cache=True):
+ super(InventoryModule, self).parse(inventory, loader, path)
+
+ self._read_config_data(path)
+
+ cache_key = self.get_cache_key(path)
+ use_cache = self.get_option("cache") and cache
+ update_cache = self.get_option("cache") and not cache
+
+ instances = None
+ if use_cache:
+ try:
+ instances = self._cache[cache_key]
+ except KeyError:
+ update_cache = True
+
+ if instances is None:
+ instances = self._get_instances()
+
+ if update_cache:
+ self._cache[cache_key] = instances
+
+ self._populate(instances)
diff --git a/ansible_collections/vultr/cloud/plugins/module_utils/vultr_v2.py b/ansible_collections/vultr/cloud/plugins/module_utils/vultr_v2.py
new file mode 100644
index 000000000..fb49d6180
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/module_utils/vultr_v2.py
@@ -0,0 +1,368 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import random
+import time
+
+from ansible.module_utils._text import to_text
+from ansible.module_utils.basic import env_fallback
+from ansible.module_utils.six.moves.urllib.parse import quote
+from ansible.module_utils.urls import fetch_url
+
+VULTR_USER_AGENT = "Ansible Vultr v2"
+
+
+def vultr_argument_spec():
+ return dict(
+ api_endpoint=dict(
+ type="str",
+ fallback=(env_fallback, ["VULTR_API_ENDPOINT"]),
+ default="https://api.vultr.com/v2",
+ ),
+ api_key=dict(
+ type="str",
+ fallback=(env_fallback, ["VULTR_API_KEY"]),
+ no_log=True,
+ required=True,
+ ),
+ api_timeout=dict(
+ type="int",
+ fallback=(env_fallback, ["VULTR_API_TIMEOUT"]),
+ default=180,
+ ),
+ api_retries=dict(
+ type="int",
+ fallback=(env_fallback, ["VULTR_API_RETRIES"]),
+ default=5,
+ ),
+ api_retry_max_delay=dict(
+ type="int",
+ fallback=(env_fallback, ["VULTR_API_RETRY_MAX_DELAY"]),
+ default=12,
+ ),
+ validate_certs=dict(
+ type="bool",
+ default=True,
+ ),
+ )
+
+
+def backoff(retry, retry_max_delay=12):
+ randomness = random.randint(0, 1000) / 1000.0
+ delay = 2**retry + randomness
+ if delay > retry_max_delay:
+ delay = retry_max_delay + randomness
+ time.sleep(delay)
+
+
+class AnsibleVultr:
+ def __init__(
+ self,
+ module,
+ namespace,
+ resource_path,
+ ressource_result_key_singular,
+ ressource_result_key_plural=None,
+ resource_key_name=None,
+ resource_key_id="id",
+ resource_get_details=False,
+ resource_create_param_keys=None,
+ resource_update_param_keys=None,
+ resource_update_method="PATCH",
+ ):
+
+ self.module = module
+ self.namespace = namespace
+
+ # The API resource path e.g ssh_key
+ self.ressource_result_key_singular = ressource_result_key_singular
+
+ # The API result data key e.g ssh_keys
+ self.ressource_result_key_plural = ressource_result_key_plural or "%ss" % ressource_result_key_singular
+
+ # The API resource path e.g /ssh-keys
+ self.resource_path = resource_path
+
+ # The name key of the resource, usually 'name'
+ self.resource_key_name = resource_key_name
+
+ # The name key of the resource, usually 'id'
+ self.resource_key_id = resource_key_id
+
+ # Some resources need an additional GET request to get all attributes
+ self.resource_get_details = resource_get_details
+
+ # List of params used to create the resource
+ self.resource_create_param_keys = resource_create_param_keys or []
+
+ # List of params used to update the resource
+ self.resource_update_param_keys = resource_update_param_keys or []
+
+ # Some resources have PUT, many have PATCH
+ self.resource_update_method = resource_update_method
+
+ self.result = {
+ "changed": False,
+ namespace: dict(),
+ "diff": dict(before=dict(), after=dict()),
+ "vultr_api": {
+ "api_timeout": module.params["api_timeout"],
+ "api_retries": module.params["api_retries"],
+ "api_retry_max_delay": module.params["api_retry_max_delay"],
+ "api_endpoint": module.params["api_endpoint"],
+ },
+ }
+
+ self.headers = {
+ "Authorization": "Bearer %s" % self.module.params["api_key"],
+ "User-Agent": VULTR_USER_AGENT,
+ "Accept": "application/json",
+ }
+
+ # Hook custom configurations
+ self.configure()
+
+ def configure(self):
+ pass
+
+ def transform_resource(self, resource):
+ """
+ Transforms (optional) the resource dict queried from the API
+ """
+ return resource
+
+ def api_query(self, path, method="GET", data=None, query_params=None):
+ if query_params:
+ query = "?"
+ for k, v in query_params.items():
+ query += "&%s=%s" % (to_text(k), quote(to_text(v)))
+ path += query
+
+ if data:
+ data = self.module.jsonify(data)
+
+ retry_max_delay = self.module.params["api_retry_max_delay"]
+
+ info = dict()
+ resp_body = None
+ for retry in range(0, self.module.params["api_retries"]):
+ resp, info = fetch_url(
+ self.module,
+ self.module.params["api_endpoint"] + path,
+ method=method,
+ data=data,
+ headers=self.headers,
+ timeout=self.module.params["api_timeout"],
+ )
+
+ resp_body = resp.read() if resp is not None else ""
+
+ # Check for:
+ # 429 Too Many Requests
+ # 500 Internal Server Error
+ if info["status"] not in (429, 500):
+ break
+
+ # Vultr has a rate limiting requests per second, try to be polite
+ # Use exponential backoff plus a little bit of randomness
+ backoff(retry=retry, retry_max_delay=retry_max_delay)
+
+ # Success with content
+ if info["status"] in (200, 201, 202):
+ return self.module.from_json(to_text(resp_body, errors="surrogate_or_strict"))
+
+ # Success without content
+ if info["status"] in (404, 204):
+ return dict()
+
+ self.module.fail_json(
+ msg='Failure while calling the Vultr API v2 with %s for "%s".' % (method, path),
+ fetch_url_info=info,
+ )
+
+ def query_filter_list_by_name(
+ self,
+ path,
+ key_name,
+ result_key,
+ param_key=None,
+ key_id=None,
+ query_params=None,
+ get_details=False,
+ fail_not_found=False,
+ skip_transform=True,
+ ):
+ param_value = self.module.params.get(param_key or key_name)
+
+ found = dict()
+ for resource in self.query_list(path=path, result_key=result_key, query_params=query_params):
+ if resource.get(key_name) == param_value:
+ if found:
+ self.module.fail_json(msg="More than one record with name=%s found. " "Use multiple=true if module supports it." % param_value)
+ found = resource
+ if found:
+ if get_details:
+ return self.query_by_id(resource_id=found[key_id], skip_transform=skip_transform)
+ else:
+ if skip_transform:
+ return found
+ else:
+ return self.transform_resource(found)
+
+ elif fail_not_found:
+ self.module.fail_json(msg="No Resource %s with %s found: %s" % (path, key_name, param_value))
+
+ return dict()
+
+ def query_filter_list(self):
+ # Returns a single dict representing the resource queryied by name
+ return self.query_filter_list_by_name(
+ key_name=self.resource_key_name,
+ key_id=self.resource_key_id,
+ get_details=self.resource_get_details,
+ path=self.resource_path,
+ result_key=self.ressource_result_key_plural,
+ skip_transform=False,
+ )
+
+ def query_by_id(self, resource_id=None, path=None, result_key=None, skip_transform=True):
+ # Defaults
+ path = path or self.resource_path
+ result_key = result_key or self.ressource_result_key_singular
+
+ resource = self.api_query(path="%s%s" % (path, "/" + resource_id if resource_id else resource_id))
+ if resource:
+ if skip_transform:
+ return resource[result_key]
+ else:
+ return self.transform_resource(resource[result_key])
+
+ return dict()
+
+ def query(self):
+ # Returns a single dict representing the resource
+ return self.query_filter_list()
+
+ def query_list(self, path=None, result_key=None, query_params=None):
+ # Defaults
+ path = path or self.resource_path
+ result_key = result_key or self.ressource_result_key_plural
+
+ resources = self.api_query(path=path, query_params=query_params)
+ return resources[result_key] if resources else []
+
+ def wait_for_state(self, resource, key, states, cmp="="):
+ for retry in range(0, 60):
+ resource = self.query_by_id(resource_id=resource[self.resource_key_id], skip_transform=False)
+ if cmp == "=":
+ if key not in resource or resource[key] in states or not resource[key]:
+ break
+ else:
+ if key not in resource or resource[key] not in states or not resource[key]:
+ break
+ backoff(retry=retry)
+ else:
+ if cmp == "=":
+ self.module.fail_json(msg="Wait for %s to become %s timed out" % (key, states))
+ else:
+ self.module.fail_json(msg="Wait for %s to not be in %s timed out" % (key, states))
+
+ return resource
+
+ def create_or_update(self):
+ resource = self.query()
+ if not resource:
+ resource = self.create()
+ else:
+ resource = self.update(resource)
+ return resource
+
+ def present(self):
+ self.get_result(self.create_or_update())
+
+ def create(self):
+ data = dict()
+ for param in self.resource_create_param_keys:
+ data[param] = self.module.params.get(param)
+
+ self.result["changed"] = True
+ resource = dict()
+
+ self.result["diff"]["before"] = dict()
+ self.result["diff"]["after"] = data
+
+ if not self.module.check_mode:
+ resource = self.api_query(
+ path=self.resource_path,
+ method="POST",
+ data=data,
+ )
+ return resource.get(self.ressource_result_key_singular) if resource else dict()
+
+ def is_diff(self, param, resource):
+ value = self.module.params.get(param)
+ if value is None:
+ return False
+
+ if param not in resource:
+ self.module.fail_json(msg="Can not diff, key %s not found in resource" % param)
+
+ if isinstance(value, list):
+ for v in value:
+ if v not in resource[param]:
+ return True
+ elif resource[param] != value:
+ return True
+
+ return False
+
+ def update(self, resource):
+ data = dict()
+
+ for param in self.resource_update_param_keys:
+ if self.is_diff(param, resource):
+ self.result["changed"] = True
+ data[param] = self.module.params.get(param)
+
+ if self.result["changed"]:
+ self.result["diff"]["before"] = dict(**resource)
+ self.result["diff"]["after"] = dict(**resource)
+ self.result["diff"]["after"].update(data)
+
+ if not self.module.check_mode:
+ self.api_query(
+ path="%s/%s" % (self.resource_path, resource[self.resource_key_id]),
+ method=self.resource_update_method,
+ data=data,
+ )
+ resource = self.query_by_id(resource_id=resource[self.resource_key_id])
+ return resource
+
+ def absent(self, resource=None):
+ if resource is None:
+ resource = self.query()
+
+ if resource:
+ self.result["changed"] = True
+
+ self.result["diff"]["before"] = dict(**resource)
+ self.result["diff"]["after"] = dict()
+
+ if not self.module.check_mode:
+ self.api_query(
+ path="%s/%s" % (self.resource_path, resource[self.resource_key_id]),
+ method="DELETE",
+ )
+ self.get_result(resource)
+
+ def transform_result(self, resource):
+ return resource
+
+ def get_result(self, resource):
+ self.result[self.namespace] = self.transform_result(resource)
+ self.module.exit_json(**self.result)
diff --git a/ansible_collections/vultr/cloud/plugins/modules/__init__.py b/ansible_collections/vultr/cloud/plugins/modules/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/__init__.py
diff --git a/ansible_collections/vultr/cloud/plugins/modules/account_info.py b/ansible_collections/vultr/cloud/plugins/modules/account_info.py
new file mode 100644
index 000000000..ecf55e2b8
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/account_info.py
@@ -0,0 +1,117 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: account_info
+short_description: Get information about the Vultr account
+description:
+ - Get infos about account balance, charges and payments.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Get Vultr account infos
+ vultr.cloud.account_info:
+ register: result
+
+- name: Print the infos
+ ansible.builtin.debug:
+ var: result.vultr_account_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_account:
+ description: Account used in the ini file to select the key.
+ returned: success
+ type: str
+ sample: default
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_account_info:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ balance:
+ description: Your account balance.
+ returned: success
+ type: float
+ sample: -214.69
+ pending_charges:
+ description: Charges pending.
+ returned: success
+ type: float
+ sample: 57.03
+ last_payment_date:
+ description: Date of the last payment.
+ returned: success
+ type: str
+ sample: "2021-11-07T05:57:59-05:00"
+ last_payment_amount:
+ description: The amount of the last payment transaction.
+ returned: success
+ type: float
+ sample: -250.0
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_account_info",
+ resource_path="/account",
+ ressource_result_key_singular="account",
+ )
+
+ vultr.get_result(vultr.query_by_id(resource_id=""))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/block_storage.py b/ansible_collections/vultr/cloud/plugins/modules/block_storage.py
new file mode 100644
index 000000000..59b8cc068
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/block_storage.py
@@ -0,0 +1,271 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: block_storage
+short_description: Manages block storage volumes on Vultr
+description:
+ - Manage block storage volumes.
+version_added: "1.0.0"
+author:
+ - "René Moser (@resmo)"
+ - "Yanis Guenane (@Spredzy)"
+options:
+ label:
+ description:
+ - Name of the block storage volume.
+ required: true
+ aliases: [ name ]
+ type: str
+ size_gb:
+ description:
+ - Size of the block storage volume in GB.
+ - Required if I(state) is present.
+ - If it is larger than the volume's current size, the volume will be resized.
+ aliases: [ size ]
+ type: int
+ block_type:
+ description:
+ - The type of block storage volume that will be created.
+ default: high_perf
+ choices: [ high_perf, storage_opt ]
+ type: str
+ version_added: "1.2.0"
+ region:
+ description:
+ - Region the block storage volume is deployed into.
+ - Required if I(state) is present.
+ type: str
+ state:
+ description:
+ - State of the block storage volume.
+ default: present
+ choices: [ present, absent]
+ type: str
+ attached_to_instance:
+ description:
+ - The ID of the server instance the volume is attached to.
+ type: str
+ live:
+ description:
+ - Whether the volume should be attached/detached without restarting the instance.
+ type: bool
+ default: false
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+---
+- name: Ensure a block storage volume is present
+ vultr.cloud.block_storage:
+ name: myvolume
+ size_gb: 10
+ block_type: storage_opt
+ region: ams
+
+- name: Ensure a block storage volume is absent
+ vultr.cloud.block_storage:
+ name: myvolume
+ state: absent
+
+- name: Ensure a block storage volume exists and is attached a server instance
+ vultr.cloud.block_storage:
+ name: myvolume
+ attached_to_instance: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ size_gb: 50
+ block_type: high_perf
+
+- name: Ensure a block storage volume exists but is not attached to any server instance
+ vultr.cloud.block_storage:
+ name: myvolume
+ attached_to_instance: ""
+ size_gb: 50
+ block_type: high_perf
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_account:
+ description: Account used in the ini file to select the key.
+ returned: success
+ type: str
+ sample: default
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_block_storage:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ attached_to_instance:
+ description: The ID of the server instance the volume is attached to.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ cost:
+ description: Cost per month for the volume.
+ returned: success
+ type: float
+ sample: 1.00
+ date_created:
+ description: Date when the volume was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ id:
+ description: ID of the block storage volume.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ label:
+ description: Label of the volume.
+ returned: success
+ type: str
+ sample: my volume
+ region:
+ description: Region the volume was deployed into.
+ returned: success
+ type: str
+ sample: ews
+ size_gb:
+ description: Information about the volume size in GB.
+ returned: success
+ type: int
+ sample: 50
+ block_type:
+ description: HDD or NVMe (storage_opt or high_perf)
+ returned: success
+ type: str
+ sample: high_perf
+ status:
+ description: Status about the deployment of the volume.
+ returned: success
+ type: str
+ sample: active
+ mount_id:
+ description: Mount ID of the volume.
+ returned: success
+ type: str
+ sample: ewr-2f5d7a314fe44f
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+class AnsibleVultrBlockStorage(AnsibleVultr):
+ def update(self, resource):
+ current_size = resource["size_gb"]
+ desired_size = self.module.params["size_gb"]
+ if desired_size < current_size:
+ self.module.params["size_gb"] = current_size
+ self.module.warn("Shrinking is not supported: current size %s, desired size %s" % (current_size, desired_size))
+ return super(AnsibleVultrBlockStorage, self).update(resource=resource)
+
+ def present(self):
+ resource = self.create_or_update() or dict()
+
+ instance_to_attach = self.module.params.get("attached_to_instance")
+ if instance_to_attach is None:
+ # exit and show result if no attach/detach needed.
+ self.get_result(resource)
+
+ instance_attached = resource.get("attached_to_instance", "")
+ if instance_attached != instance_to_attach:
+ self.result["changed"] = True
+
+ mode = "detach" if not instance_to_attach else "attach"
+ self.result["diff"]["after"].update({"attached_to_instance": instance_to_attach})
+
+ data = {
+ "instance_id": instance_to_attach if instance_to_attach else None,
+ "live": self.module.params.get("live"),
+ }
+
+ if not self.module.check_mode:
+ self.api_query(
+ path="%s/%s/%s" % (self.resource_path, resource[self.resource_key_id], mode),
+ method="POST",
+ data=data,
+ )
+ resource = self.query_by_id(resource_id=resource[self.resource_key_id])
+
+ self.get_result(resource)
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ label=dict(type="str", required=True, aliases=["name"]),
+ size_gb=dict(type="int", aliases=["size"]),
+ block_type=dict(type="str", choices=["high_perf", "storage_opt"], default="high_perf"),
+ region=dict(type="str"),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ attached_to_instance=dict(type="str"),
+ live=dict(type="bool", default=False),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "present", ["size_gb", "region"]],
+ ],
+ )
+
+ vultr = AnsibleVultrBlockStorage(
+ module=module,
+ namespace="vultr_block_storage",
+ resource_path="/blocks",
+ ressource_result_key_singular="block",
+ resource_create_param_keys=["label", "size_gb", "region", "block_type"],
+ resource_update_param_keys=["size_gb"],
+ resource_key_name="label",
+ # Query details information about block type
+ resource_get_details=True,
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/block_storage_info.py b/ansible_collections/vultr/cloud/plugins/modules/block_storage_info.py
new file mode 100644
index 000000000..a52591d94
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/block_storage_info.py
@@ -0,0 +1,139 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: block_storage_info
+short_description: Get information about the Vultr block storage
+version_added: "1.0.0"
+description:
+ - Get infos about block storages available.
+author:
+ - "René Moser (@resmo)"
+ - "Yanis Guenane (@Spredzy)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Get Vultr block_storage infos
+ vultr.cloud.block_storage_info:
+ register: result
+
+- name: Print the infos
+ ansible.builtin.debug:
+ var: result.vultr_block_storage_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_block_storage_info:
+ description: Response from Vultr API as list.
+ returned: success
+ type: list
+ contains:
+ attached_to_instance:
+ description: The ID of the server instance the volume is attached to.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ cost:
+ description: Cost per month for the volume.
+ returned: success
+ type: float
+ sample: 1.00
+ date_created:
+ description: Date when the volume was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ id:
+ description: ID of the block storage volume.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ label:
+ description: Label of the volume.
+ returned: success
+ type: str
+ sample: my volume
+ region:
+ description: Region the volume was deployed into.
+ returned: success
+ type: str
+ sample: ews
+ size_gb:
+ description: Information about the volume size in GB.
+ returned: success
+ type: int
+ sample: 50
+ status:
+ description: Status about the deployment of the volume.
+ returned: success
+ type: str
+ sample: active
+ mount_id:
+ description: Mount ID of the volume.
+ returned: success
+ type: str
+ sample: ewr-2f5d7a314fe44f
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_block_storage_info",
+ resource_path="/blocks",
+ ressource_result_key_singular="block",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/dns_domain.py b/ansible_collections/vultr/cloud/plugins/modules/dns_domain.py
new file mode 100644
index 000000000..3f0132b0c
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/dns_domain.py
@@ -0,0 +1,155 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: dns_domain
+short_description: Manages DNS domains on Vultr
+description:
+ - Create and remove DNS domains.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+options:
+ domain:
+ description:
+ - The domain name.
+ required: true
+ aliases: [ name ]
+ type: str
+ ip:
+ description:
+ - The default server IP.
+ - Use M(vultr.cloud.dns_record) to change it once the domain is created.
+ - Required if C(state=present).
+ type: str
+ aliases: [ server_ip ]
+ dns_sec:
+ description:
+ - Ensure DNSSEC is enabled or disabled.
+ type: str
+ choices: [ enabled, disabled ]
+ default: disabled
+ state:
+ description:
+ - State of the DNS domain.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Ensure a domain exists with DNSSEC
+ vultr.cloud.dns_domain:
+ name: example.com
+ dns_sec: enabled
+ server_ip: 10.10.10.10
+
+- name: Ensure a domain is absent
+ vultr.cloud.dns_domain:
+ name: example.com
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_dns_domain:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ name:
+ description: Name of the DNS Domain.
+ returned: success
+ type: str
+ sample: example.com
+ dns_sec:
+ description: Whether DNSSEC is enabled or disabled.
+ returned: success
+ type: str
+ sample: disabled
+ date_created:
+ description: Date the DNS domain was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ domain=dict(type="str", required=True, aliases=["name"]),
+ ip=dict(type="str", aliases=["server_ip"]),
+ dns_sec=dict(type="str", choices=["enabled", "disabled"], default="disabled"),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=[
+ ("state", "present", ["ip"]),
+ ],
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_dns_domain",
+ resource_path="/domains",
+ ressource_result_key_singular="domain",
+ resource_create_param_keys=["domain", "dns_sec", "ip"],
+ resource_update_param_keys=["domain", "dns_sec"],
+ resource_key_name="domain",
+ resource_key_id="domain",
+ resource_update_method="PUT",
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/dns_domain_info.py b/ansible_collections/vultr/cloud/plugins/modules/dns_domain_info.py
new file mode 100644
index 000000000..aa198b176
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/dns_domain_info.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: dns_domain_info
+short_description: Gather information about the Vultr DNS domains
+description:
+ - Gather information about DNS domains available.
+version_added: "1.0.0"
+author:
+ - "Yanis Guenane (@Spredzy)"
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Gather Vultr DNS domains information
+ vultr.cloud.dns_domain_info:
+ register: result
+
+- name: Print the gathered information
+ ansible.builtin.debug:
+ var: result.vultr_dns_domain_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_dns_domain_info:
+ description: Response from Vultr API as list.
+ returned: success
+ type: list
+ contains:
+ domain:
+ description: Name of the DNS Domain.
+ returned: success
+ type: str
+ sample: example.com
+ dns_sec:
+ description: Whether DNSSEC is enabled or disabled.
+ returned: success
+ type: str
+ sample: disabled
+ date_created:
+ description: Date the DNS domain was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_dns_domain_info",
+ resource_path="/domains",
+ ressource_result_key_singular="domain",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/dns_record.py b/ansible_collections/vultr/cloud/plugins/modules/dns_record.py
new file mode 100644
index 000000000..2e4352e93
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/dns_record.py
@@ -0,0 +1,267 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: dns_record
+short_description: Manages DNS records on Vultr
+description:
+ - Create, update and remove DNS records.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+options:
+ name:
+ description:
+ - The record name.
+ type: str
+ default: ""
+ domain:
+ description:
+ - The domain the record is related to.
+ type: str
+ required: true
+ type:
+ description:
+ - Type of the record.
+ default: A
+ choices:
+ - A
+ - AAAA
+ - CNAME
+ - NS
+ - MX
+ - SRV
+ - TXT
+ - CAA
+ - SSHFP
+ aliases: [ record_type ]
+ type: str
+ data:
+ description:
+ - Data of the record.
+ - Required if C(state=present).
+ type: str
+ ttl:
+ description:
+ - TTL of the record.
+ default: 300
+ type: int
+ priority:
+ description:
+ - Priority of the record.
+ type: int
+ multiple:
+ description:
+ - Whether to use more than one record with similar I(name) including no name and I(type).
+ - Only allowed for a few record types, e.g. C(type=A), C(type=NS) or C(type=MX).
+ - I(data) will not be updated, instead it is used as a key to find existing records.
+ default: false
+ type: bool
+ state:
+ description:
+ - State of the DNS record.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+
+EXAMPLES = """
+- name: Ensure an A record exists
+ vultr.cloud.dns_record:
+ name: www
+ domain: example.com
+ data: 10.10.10.10
+ ttl: 3600
+
+- name: Ensure a second A record exists for round robin LB
+ vultr.cloud.dns_record:
+ name: www
+ domain: example.com
+ data: 10.10.10.11
+ ttl: 60
+ multiple: true
+
+- name: Ensure a CNAME record exists
+ vultr.cloud.dns_record:
+ name: web
+ type: CNAME
+ domain: example.com
+ data: www.example.com
+
+- name: Ensure MX record exists
+ vultr.cloud.dns_record:
+ type: MX
+ domain: example.com
+ data: "{{ item.data }}"
+ priority: "{{ item.priority }}"
+ multiple: true
+ with_items:
+ - { data: mx1.example.com, priority: 10 }
+ - { data: mx2.example.com, priority: 10 }
+ - { data: mx3.example.com, priority: 20 }
+
+- name: Ensure a record is absent
+ vultr.cloud.dns_record:
+ name: www
+ domain: example.com
+ state: absent
+
+- name: Ensure one MX record is absent if multiple exists
+ vultr.cloud.dns_record:
+ record_type: MX
+ domain: example.com
+ data: mx1.example.com
+ multiple: true
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+dns_record:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: The ID of the DNS record.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ name:
+ description: The name of the DNS record.
+ returned: success
+ type: str
+ sample: web
+ type:
+ description: The name of the DNS record.
+ returned: success
+ type: str
+ sample: A
+ data:
+ description: Data of the DNS record.
+ returned: success
+ type: str
+ sample: 10.10.10.10
+ priority:
+ description: Priority of the DNS record.
+ returned: success
+ type: int
+ sample: 10
+ ttl:
+ description: Time to live of the DNS record.
+ returned: success
+ type: int
+ sample: 300
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+RECORD_TYPES = ["A", "AAAA", "CNAME", "MX", "TXT", "NS", "SRV", "CAA", "SSHFP"]
+
+
+class AnsibleVultrDnsRecord(AnsibleVultr):
+ def query(self):
+ multiple = self.module.params.get("multiple")
+ name = self.module.params.get("name")
+ data = self.module.params.get("data")
+ record_type = self.module.params.get("type")
+
+ result = dict()
+ for resource in self.query_list():
+ if resource.get("type") != record_type:
+ continue
+
+ if resource.get("name") == name:
+ if not multiple:
+ if result:
+ self.module.fail_json(
+ msg="More than one record with record_type=%s and name=%s params. "
+ "Use multiple=true for more than one record." % (record_type, name)
+ )
+ else:
+ result = resource
+ elif resource.get("data") == data:
+ return resource
+ return result
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ domain=dict(type="str", required=True),
+ name=dict(type="str", default=""),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ttl=dict(type="int", default=300),
+ type=dict(type="str", choices=RECORD_TYPES, default="A", aliases=["record_type"]),
+ multiple=dict(type="bool", default=False),
+ priority=dict(type="int"),
+ data=dict(type="str"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=[
+ ("state", "present", ["data"]),
+ ("multiple", True, ["data"]),
+ ],
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultrDnsRecord(
+ module=module,
+ namespace="vultr_dns_record",
+ resource_path="/domains/%s/records" % module.params.get("domain"), # type: ignore
+ ressource_result_key_singular="record",
+ resource_create_param_keys=["name", "ttl", "data", "priority", "type"],
+ resource_update_param_keys=["name", "ttl", "data", "priority"],
+ resource_key_name="name",
+ ) # type: ignore
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/firewall_group.py b/ansible_collections/vultr/cloud/plugins/modules/firewall_group.py
new file mode 100644
index 000000000..962936a78
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/firewall_group.py
@@ -0,0 +1,138 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: firewall_group
+short_description: Manages firewall groups on Vultr
+description:
+ - Create and remove firewall groups.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+options:
+ description:
+ description:
+ - Description of the firewall group.
+ required: true
+ aliases: [ name ]
+ type: str
+ state:
+ description:
+ - State of the firewall group.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: ensure a firewall group is present
+ vultr.cloud.firewall_group:
+ description: my http firewall.
+
+- name: ensure a firewall group is absent
+ vultr.cloud.firewall_group:
+ description: my http firewall.
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_firewall_group:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: ID of the firewall group.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ description:
+ description: Description (name) of the firewall group
+ returned: success
+ type: str
+ sample: my firewall group
+ date_created:
+ description: Date the firewall group was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ date_modified:
+ description: Date the firewall group was modified.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ description=dict(type="str", required=True, aliases=["name"]),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_firewall_group",
+ resource_path="/firewalls",
+ ressource_result_key_singular="firewall_group",
+ resource_create_param_keys=["description"],
+ resource_update_param_keys=["description"],
+ resource_key_name="description",
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/firewall_group_info.py b/ansible_collections/vultr/cloud/plugins/modules/firewall_group_info.py
new file mode 100644
index 000000000..866ac4818
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/firewall_group_info.py
@@ -0,0 +1,114 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: firewall_group_info
+short_description: Gather information about the Vultr firewall groups
+description:
+ - Gather information about firewall groups available.
+version_added: "1.0.0"
+author:
+ - "Yanis Guenane (@Spredzy)"
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Gather Vultr firewall groups information
+ vultr.cloud.firewall_group_info:
+ register: result
+
+- name: Print the gathered information
+ ansible.builtin.debug:
+ var: result.vultr_firewall_group_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_firewall_group_info:
+ description: Response from Vultr API as list.
+ returned: success
+ type: list
+ contains:
+ id:
+ description: ID of the firewall group.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ description:
+ description: Name of the firewall group.
+ returned: success
+ type: str
+ sample: my firewall group
+ date_created:
+ description: Date the firewall group was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ date_modified:
+ description: Date the firewall group was modified.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_firewall_group_info",
+ resource_path="/firewalls",
+ ressource_result_key_singular="firewall_group",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/firewall_rule.py b/ansible_collections/vultr/cloud/plugins/modules/firewall_rule.py
new file mode 100644
index 000000000..474372d08
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/firewall_rule.py
@@ -0,0 +1,297 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: firewall_rule
+short_description: Manages firewall rules on Vultr
+description:
+ - Create and remove firewall rules.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+options:
+ group:
+ description:
+ - Name of the firewall group.
+ required: true
+ type: str
+ ip_type:
+ description:
+ - IP address version
+ choices: [ v4, v6 ]
+ type: str
+ default: v4
+ protocol:
+ description:
+ - Protocol of the firewall rule.
+ choices: [ icmp, tcp, udp, gre, esp, ah ]
+ type: str
+ default: tcp
+ subnet:
+ description:
+ - The network or IP, e.g. 192.0.2.123 or 0.0.0.0.
+ - Mutally exclusive with I(source).
+ type: str
+ subnet_size:
+ description:
+ - The number of bits for the netmask in CIDR notation, e.g. C(32).
+ type: int
+ port:
+ description:
+ - Single port or port range, e.g. C(80) or C(8000:8080).
+ - Required if I(protocol) is tcp or udp and I(state=present).
+ aliases: [ port_range ]
+ type: str
+ source:
+ description:
+ - Possible values are C(cloudflare) or a loadbalancer label.
+ - Mutally exclusive with I(subnet).
+ type: str
+ notes:
+ description:
+ - Notes of the firewall rule.
+ type: str
+ state:
+ description:
+ - State of the firewall rule.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Ensure a firewall rule is present
+ vultr.cloud.firewall_rule:
+ group: web
+ port: 80
+ protocol: tcp
+ ip_type: v4
+ subnet: "0.0.0.0"
+ subnet_size: 0
+ notes: "open HTTP to the world"
+
+- name: Ensure a firewall rule with port range is present
+ vultr.cloud.firewall_rule:
+ group: apps
+ port: "8000:8999"
+ protocol: tcp
+ ip_type: v4
+ subnet: "10.10.10.0"
+ subnet_size: 24
+
+- name: Ensure a firewall rule is absent
+ vultr.cloud.firewall_rule:
+ group: apps
+ port: "443"
+ protocol: tcp
+ ip_type: v6
+ subnet: "::"
+ subnet_size: 0
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_firewall_rule:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: ID of the firewall rule.
+ returned: success
+ type: int
+ sample: 1
+ action:
+ description: Action of the firewall rule.
+ returned: success
+ type: str
+ sample: accept
+ protocol:
+ description: Protocol of the firewall rule.
+ returned: success
+ type: str
+ sample: tcp
+ port:
+ description: Port or port range of the firewall rule.
+ returned: success
+ type: str
+ sample: "80"
+ source:
+ description: Source string of the firewall rule.
+ returned: success
+ type: str
+ sample: cloudflare
+ notes:
+ description: Supplied description of the firewall rule.
+ returned: success
+ type: str
+ sample: my rule
+ subnet:
+ description: Subnet of the firewall rule.
+ returned: success
+ type: str
+ sample: 0.0.0.0
+ subnet_size:
+ description: Size of the subnet of the firewall rule.
+ returned: success
+ type: int
+ sample: 0
+ ip_type:
+ description: IP type of the firewall rule.
+ returned: success
+ type: str
+ sample: v4
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+class AnsibleVultrFirewallRule(AnsibleVultr):
+ def get_firewall_group(self):
+ return self.query_filter_list_by_name(
+ key_name="description",
+ param_key="group",
+ path="/firewalls",
+ result_key="firewall_groups",
+ fail_not_found=True,
+ )
+
+ def get_load_balancer(self):
+ return self.query_filter_list_by_name(
+ key_name="label",
+ param_key="source",
+ path="/load-balancers",
+ result_key="load_balancers",
+ fail_not_found=True,
+ )
+
+ def configure(self):
+ # Set firewall group id to resource path, ensures firewall group exists
+ self.resource_path = self.resource_path % self.get_firewall_group()["id"]
+
+ # Set loadbalancer ID for source
+ source = self.module.params.get("source")
+ if source is not None and source != "cloudflare":
+ self.module.params["source"] = self.get_load_balancer()["id"]
+
+ def query(self):
+ result = dict()
+ for resource in self.query_list():
+ for key in (
+ "ip_type",
+ "protocol",
+ "port",
+ "source",
+ "subnet",
+ "subnet_size",
+ ):
+ param = self.module.params.get(key)
+
+ if param is None:
+ continue
+
+ if resource.get(key) != param:
+ break
+ else:
+ result = resource
+
+ if result:
+ break
+
+ return result
+
+ def update(self, resource):
+ return resource
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ notes=dict(type="str"),
+ group=dict(type="str", required=True),
+ port=dict(type="str", aliases=["port_range"]),
+ subnet=dict(type="str"),
+ subnet_size=dict(type="int"),
+ source=dict(type="str"),
+ protocol=dict(
+ type="str",
+ choices=["icmp", "tcp", "udp", "gre", "esp", "ah"],
+ default="tcp",
+ ),
+ ip_type=dict(type="str", choices=["v4", "v6"], default="v4"),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_one_of=(("source", "subnet"),),
+ mutually_exclusive=(("source", "subnet"),),
+ required_together=(("subnet", "subnet_size"),),
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultrFirewallRule(
+ module=module,
+ namespace="vultr_firewall_rule",
+ resource_path="/firewalls/%s/rules",
+ ressource_result_key_singular="firewall_rule",
+ resource_key_name="##unused##",
+ resource_create_param_keys=[
+ "notes",
+ "port",
+ "subnet",
+ "subnet_size",
+ "source",
+ "protocol",
+ "ip_type",
+ ],
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/firewall_rule_info.py b/ansible_collections/vultr/cloud/plugins/modules/firewall_rule_info.py
new file mode 100644
index 000000000..6d51d6f9c
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/firewall_rule_info.py
@@ -0,0 +1,162 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: firewall_rule_info
+short_description: Gather information about the Vultr firewall rules
+description:
+ - Gather information about firewall rules available.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+options:
+ group:
+ description:
+ - Name of the firewall group.
+ required: true
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Gather Vultr firewall rule information
+ vultr.cloud.firewall_rule_info:
+ group: my group
+ register: result
+
+- name: Print the gathered information
+ ansible.builtin.debug:
+ var: result.vultr_firewall_rule_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_firewall_rule_info:
+ description: Response from Vultr API as list.
+ returned: success
+ type: list
+ contains:
+ id:
+ description: ID of the firewall rule.
+ returned: success
+ type: int
+ sample: 1
+ action:
+ description: Action of the firewall rule.
+ returned: success
+ type: str
+ sample: accept
+ protocol:
+ description: Protocol of the firewall rule.
+ returned: success
+ type: str
+ sample: tcp
+ port:
+ description: Port or port range of the firewall rule.
+ returned: success
+ type: str
+ sample: "80"
+ source:
+ description: Source string of the firewall rule.
+ returned: success
+ type: str
+ sample: cloudflare
+ notes:
+ description: Supplied description of the firewall rule.
+ returned: success
+ type: str
+ sample: my rule
+ subnet:
+ description: Subnet of the firewall rule.
+ returned: success
+ type: str
+ sample: 0.0.0.0
+ subnet_size:
+ description: Size of the subnet of the firewall rule.
+ returned: success
+ type: int
+ sample: 0
+ ip_type:
+ description: IP type of the firewall rule.
+ returned: success
+ type: str
+ sample: v4
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+class AnsibleVultrFirewallRuleInfo(AnsibleVultr):
+ def get_firewall_group(self):
+ return self.query_filter_list_by_name(
+ key_name="description",
+ param_key="group",
+ path="/firewalls",
+ result_key="firewall_groups",
+ fail_not_found=True,
+ )
+
+ def configure(self):
+ # Set firewall group id to resource path, ensures firewall group exists
+ self.resource_path = self.resource_path % self.get_firewall_group()["id"]
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ group=dict(type="str", required=True),
+ ) # type: ignore
+ )
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultrFirewallRuleInfo(
+ module=module,
+ namespace="vultr_firewall_rule_info",
+ resource_path="/firewalls/%s/rules",
+ ressource_result_key_singular="firewall_rule",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/instance.py b/ansible_collections/vultr/cloud/plugins/modules/instance.py
new file mode 100644
index 000000000..73099164d
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/instance.py
@@ -0,0 +1,739 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: instance
+short_description: Manages server instances on Vultr.
+description:
+ - Manage server instances on Vultr.
+version_added: "1.1.0"
+author:
+ - "René Moser (@resmo)"
+options:
+ label:
+ description:
+ - Name of the instance.
+ required: true
+ aliases: [ name ]
+ type: str
+ hostname:
+ description:
+ - The hostname to assign to this instance.
+ type: str
+ os:
+ description:
+ - The operating system name.
+ - Mutually exclusive with I(image) and I(app).
+ type: str
+ app:
+ description:
+ - The app deploy name of Vultr OneClick apps.
+ - Mutually exclusive with I(image) and I(os).
+ type: str
+ image:
+ description:
+ - The image deploy name of Vultr Marketplace apps.
+ - Mutually exclusive with I(os) and I(app).
+ type: str
+ firewall_group:
+ description:
+ - The firewall group description to assign this instance to.
+ type: str
+ plan:
+ description:
+ - The plan name to use for the instance.
+ - Required if the instance does not yet exist.
+ type: str
+ activation_email:
+ description:
+ - Whether to send an activation email when the instance is ready or not.
+ - Only considered on creation.
+ type: bool
+ default: false
+ backups:
+ description:
+ - Whether to enable automatic backups or not.
+ type: bool
+ ddos_protection:
+ description:
+ - Whether to enable ddos_protection or not.
+ type: bool
+ enable_ipv6:
+ description:
+ - Whether to enable IPv6 or not.
+ type: bool
+ tags:
+ description:
+ - Tags for the instance.
+ type: list
+ elements: str
+ user_data:
+ description:
+ - User data to be passed to the instance.
+ type: str
+ startup_script:
+ description:
+ - Name or ID of the startup script to execute on boot.
+ - Only considered while creating the instance.
+ type: str
+ ssh_keys:
+ description:
+ - List of SSH key names passed to the instance on creation.
+ type: list
+ elements: str
+ snapshot:
+ description:
+ - Description or ID of the snapshot.
+ - Only considered while creating the instance.
+ type: str
+ version_added: "1.7.0"
+ reserved_ipv4:
+ description:
+ - IP address of the floating IP to use as the main IP of this instance.
+ - Only considered on creation.
+ type: str
+ region:
+ description:
+ - Region the instance is deployed into.
+ type: str
+ required: true
+ vpcs:
+ description:
+ - A list of VPCs identified by their description to be assigned to the instance.
+ type: list
+ elements: str
+ version_added: "1.5.0"
+ state:
+ description:
+ - State of the instance.
+ - The state I(reinstalled) was added in version 1.8.0.
+ default: present
+ choices: [ present, absent, started, stopped, restarted, reinstalled ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+---
+- name: Create an instance using OS
+ vultr.cloud.instance:
+ label: my web server
+ hostname: my-hostname
+ user_data: |
+ #cloud-config
+ packages:
+ - nginx
+ firewall_group: my firewall group
+ plan: vc2-1c-2gb
+ ddos_protection: true
+ backups: true
+ enable_ipv6: true
+ ssh_keys:
+ - my ssh key
+ vpcs:
+ - my vpc description
+ tags:
+ - web
+ - project-genesis
+ region: ams
+ os: Debian 11 x64 (bullseye)
+
+- name: Deploy an instance of a marketplace app
+ vultr.cloud.instance:
+ label: git-server
+ hostname: git
+ firewall_group: my firewall group
+ plan: vc2-1c-2gb
+ ddos_protection: true
+ backups: true
+ enable_ipv6: true
+ region: ams
+ image: Gitea on Ubuntu 20.04
+
+- name: Stop an existing instance
+ vultr.cloud.instance:
+ label: my web server
+ region: ams
+ state: stopped
+
+- name: Start an existing instance
+ vultr.cloud.instance:
+ label: my web server
+ region: ams
+ state: started
+
+- name: Reinstall an instance
+ vultr.cloud.instance:
+ label: my web server
+ region: ams
+ state: reinstalled
+
+- name: Delete an instance
+ vultr.cloud.instance:
+ label: my web server
+ region: ams
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_instance:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: ID of the instance.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ v6_main_ip:
+ description: IPv6 of the instance.
+ returned: success
+ type: str
+ sample: ""
+ v6_network:
+ description: IPv6 network of the instance.
+ returned: success
+ type: str
+ sample: ""
+ v6_network_size:
+ description: IPv6 network size of the instance.
+ returned: success
+ type: int
+ sample: 0
+ main_ip:
+ description: IPv4 of the instance.
+ returned: success
+ type: str
+ sample: 95.179.189.95
+ netmask_v4:
+ description: Netmask IPv4 of the instance.
+ returned: success
+ type: str
+ sample: 255.255.254.0
+ hostname:
+ description: Hostname of the instance.
+ returned: success
+ type: str
+ sample: vultr.guest
+ internal_ip:
+ description: Internal IP of the instance.
+ returned: success
+ type: str
+ sample: ""
+ gateway_v4:
+ description: Gateway IPv4.
+ returned: success
+ type: str
+ sample: 95.179.188.1
+ kvm:
+ description: KVM of the instance.
+ returned: success
+ type: str
+ sample: "https://my.vultr.com/subs/vps/novnc/api.php?data=..."
+ disk:
+ description: Disk size of the instance.
+ returned: success
+ type: int
+ sample: 25
+ allowed_bandwidth:
+ description: Allowed bandwidth of the instance.
+ returned: success
+ type: int
+ sample: 1000
+ vcpu_count:
+ description: vCPUs of the instance.
+ returned: success
+ type: int
+ sample: 1
+ firewall_group_id:
+ description: Firewall group ID of the instance.
+ returned: success
+ type: str
+ sample: ""
+ plan:
+ description: Plan of the instance.
+ returned: success
+ type: str
+ sample: vc2-1c-1gb
+ image_id:
+ description: Image ID of the instance.
+ returned: success
+ type: str
+ sample: ""
+ os_id:
+ description: OS ID of the instance.
+ returned: success
+ type: int
+ sample: 186
+ app_id:
+ description: App ID of the instance.
+ returned: success
+ type: int
+ sample: 37
+ date_created:
+ description: Date when the instance was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ label:
+ description: Label of the instance.
+ returned: success
+ type: str
+ sample: my instance
+ region:
+ description: Region the instance was deployed into.
+ returned: success
+ type: str
+ sample: ews
+ status:
+ description: Status about the deployment of the instance.
+ returned: success
+ type: str
+ sample: active
+ server_status:
+ description: Server status of the instance.
+ returned: success
+ type: str
+ sample: installingbooting
+ power_status:
+ description: Power status of the instance.
+ returned: success
+ type: str
+ sample: running
+ ram:
+ description: RAM in MB of the instance.
+ returned: success
+ type: int
+ sample: 1024
+ os:
+ description: OS of the instance.
+ returned: success
+ type: str
+ sample: Application
+ tags:
+ description: Tags of the instance.
+ returned: success
+ type: list
+ sample: [ my-tag ]
+ features:
+ description: Features of the instance.
+ returned: success
+ type: list
+ sample: [ ddos_protection, ipv6, auto_backups ]
+ user_data:
+ description: Base64 encoded user data (cloud init) of the instance.
+ returned: success
+ type: str
+ sample: I2Nsb3VkLWNvbmZpZwpwYWNrYWdlczoKICAtIGh0b3AK
+ backups:
+ description: Whether backups are enabled or disabled.
+ returned: success
+ type: str
+ sample: enabled
+ version_added: "1.3.0"
+ ddos_protection:
+ description: Whether DDOS protections is enabled or not.
+ returned: success
+ type: bool
+ sample: true
+ version_added: "1.3.0"
+ enable_ipv6:
+ description: Whether IPv6 is enabled or not.
+ returned: success
+ type: bool
+ sample: true
+ version_added: "1.3.0"
+ vpcs:
+ description: List of VPCs attached.
+ returned: success
+ type: list
+ version_added: "1.5.0"
+ contains:
+ id:
+ description: ID of the VPC.
+ returned: success
+ type: str
+ sample: 5536d2a4-66fd-4dfb-b839-7672fd5bc116
+ description:
+ description: Description of the VPC.
+ returned: success
+ type: str
+ sample: my vpc
+ ip_address:
+ description: IP assigned from the VPC.
+ returned: success
+ type: str
+ sample: "192.168.23.3"
+ mac_address:
+ description: MAC address of the network interface.
+ returned: success
+ type: str
+ sample: "5a:01:04:3d:5e:72"
+"""
+
+import base64
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+class AnsibleVultrInstance(AnsibleVultr):
+ def get_ssh_key_ids(self):
+ ssh_key_names = list(self.module.params["ssh_keys"])
+ ssh_keys = self.query_list(path="/ssh-keys", result_key="ssh_keys")
+
+ ssh_key_ids = list()
+ for ssh_key in ssh_keys:
+ if ssh_key["name"] in ssh_key_names:
+ ssh_key_ids.append(ssh_key["id"])
+ ssh_key_names.remove(ssh_key["name"])
+
+ if ssh_key_names:
+ self.module.fail_json(msg="SSH key names not found: %s" % ", ".join(ssh_key_names))
+
+ return ssh_key_ids
+
+ def get_vpc_ids(self):
+ vpc_names = list(self.module.params["vpcs"])
+ vpcs = self.query_list(path="/vpcs", result_key="vpcs")
+
+ vpc_ids = list()
+ for vpc in vpcs:
+ if vpc["description"] in vpc_names:
+ vpc_ids.append(vpc["id"])
+ vpc_names.remove(vpc["description"])
+
+ if vpc_names:
+ self.module.fail_json(msg="VPCs not found: %s" % ", ".join(vpc_names))
+
+ return vpc_ids
+
+ def get_instance_vpcs(self, resource):
+ path = "/instances/%s/vpcs" % resource["id"]
+ vpcs = self.query_list(path=path, result_key="vpcs")
+
+ # Workaround to get the description field into the list
+ result = list()
+ for vpc in vpcs:
+ vpc_detail = self.query_by_id(resource_id=vpc["id"], path="/vpcs", result_key="vpc")
+ vpc["description"] = vpc_detail["description"]
+ result.append(vpc)
+ return result
+
+ def get_firewall_group(self):
+ return self.query_filter_list_by_name(
+ key_name="description",
+ param_key="firewall_group",
+ path="/firewalls",
+ result_key="firewall_groups",
+ fail_not_found=True,
+ )
+
+ def get_snapshot(self):
+ return self.query_filter_list_by_name(
+ key_name="description",
+ param_key="snapshot",
+ path="/snapshots",
+ result_key="snapshots",
+ fail_not_found=True,
+ )
+
+ def get_startup_script(self):
+ return self.query_filter_list_by_name(
+ key_name="name",
+ param_key="startup_script",
+ path="/startup-scripts",
+ result_key="startup_scripts",
+ fail_not_found=True,
+ )
+
+ def get_os(self):
+ return self.query_filter_list_by_name(
+ key_name="name",
+ param_key="os",
+ path="/os",
+ result_key="os",
+ fail_not_found=True,
+ )
+
+ def get_app(self):
+ return self.query_filter_list_by_name(
+ key_name="deploy_name",
+ param_key="app",
+ path="/applications",
+ result_key="applications",
+ fail_not_found=True,
+ query_params={"type": "one-click"},
+ )
+
+ def get_image(self):
+ return self.query_filter_list_by_name(
+ key_name="deploy_name",
+ param_key="image",
+ path="/applications",
+ result_key="applications",
+ fail_not_found=True,
+ query_params={"type": "marketplace"},
+ )
+
+ def get_user_data(self, resource):
+ res = self.api_query(
+ path="%s/%s/%s" % (self.resource_path, resource[self.resource_key_id], "user-data"),
+ )
+ if res:
+ return str(res.get("user_data", dict()).get("data"))
+ return ""
+
+ def transform_resource(self, resource):
+ if not resource:
+ return resource
+
+ features = resource.get("features", list())
+ resource["backups"] = "enabled" if "auto_backups" in features else "disabled"
+ resource["enable_ipv6"] = "ipv6" in features
+ resource["ddos_protection"] = "ddos_protection" in features
+ resource["vpcs"] = self.get_instance_vpcs(resource=resource)
+
+ return resource
+
+ def get_detach_vpcs_ids(self, resource):
+ detach_vpc_ids = []
+ for vpc in resource.get("vpcs", list()):
+ if vpc["id"] not in list(self.module.params["attach_vpc"]):
+ detach_vpc_ids.append(vpc["id"])
+ return detach_vpc_ids
+
+ def configure(self):
+ if self.module.params["state"] != "absent":
+ if self.module.params["startup_script"] is not None:
+ self.module.params["script_id"] = self.get_startup_script()["id"]
+
+ if self.module.params["snapshot"] is not None:
+ self.module.params["snapshot_id"] = self.get_snapshot()["id"]
+
+ if self.module.params["firewall_group"] is not None:
+ self.module.params["firewall_group_id"] = self.get_firewall_group()["id"]
+
+ if self.module.params["os"] is not None:
+ self.module.params["os_id"] = self.get_os()["id"]
+
+ if self.module.params["app"] is not None:
+ self.module.params["app_id"] = self.get_app()["id"]
+
+ if self.module.params["image"] is not None:
+ self.module.params["image_id"] = self.get_image()["image_id"]
+
+ if self.module.params["user_data"] is not None:
+ self.module.params["user_data"] = base64.b64encode(self.module.params["user_data"].encode())
+
+ if self.module.params["ssh_keys"] is not None:
+ # sshkey_id ist a list of ids
+ self.module.params["sshkey_id"] = self.get_ssh_key_ids()
+
+ if self.module.params["backups"] is not None:
+ self.module.params["backups"] = "enabled" if self.module.params["backups"] else "disabled"
+
+ if self.module.params["vpcs"] is not None:
+ # attach_vpc is a list of ids used while creating
+ self.module.params["attach_vpc"] = self.get_vpc_ids()
+
+ def handle_power_status(self, resource, state, action, power_status, force=False, wait_for_state=True):
+ if state == self.module.params["state"] and (resource["power_status"] != power_status or force):
+ self.result["changed"] = True
+ if not self.module.check_mode:
+ resource = self.wait_for_state(resource=resource, key="server_status", states=["none", "locked"], cmp="!=")
+ self.api_query(
+ path="%s/%s/%s" % (self.resource_path, resource[self.resource_key_id], action),
+ method="POST",
+ )
+ if wait_for_state:
+ resource = self.wait_for_state(resource=resource, key="power_status", states=[power_status])
+ return resource
+
+ def create(self):
+ param_keys = ("os", "image", "app", "snapshot")
+ if not any(self.module.params.get(x) is not None for x in param_keys):
+ self.module.fail_json(msg="missing required arguements, one of the following required: %s" % ", ".join(param_keys))
+ return super(AnsibleVultrInstance, self).create()
+
+ def update(self, resource):
+ user_data = self.get_user_data(resource=resource)
+ resource["user_data"] = user_data.encode()
+
+ if self.module.params["vpcs"] is not None:
+ resource["attach_vpc"] = list()
+ for vpc in list(resource["vpcs"]):
+ resource["attach_vpc"].append(vpc["id"])
+
+ # detach_vpc is a list of ids to be detached
+ resource["detach_vpc"] = list()
+ self.module.params["detach_vpc"] = self.get_detach_vpcs_ids(resource=resource)
+
+ return super(AnsibleVultrInstance, self).update(resource=resource)
+
+ def create_or_update(self):
+ resource = super(AnsibleVultrInstance, self).create_or_update()
+ if resource:
+ resource = self.wait_for_state(resource=resource, key="status", states=["active"])
+ resource = self.wait_for_state(resource=resource, key="server_status", states=["none", "locked"], cmp="!=")
+
+ # Hanlde power status
+ resource = self.handle_power_status(resource=resource, state="stopped", action="halt", power_status="stopped")
+ resource = self.handle_power_status(resource=resource, state="started", action="start", power_status="running")
+ resource = self.handle_power_status(resource=resource, state="restarted", action="reboot", power_status="running", force=True)
+ resource = self.handle_power_status(
+ resource=resource,
+ state="reinstalled",
+ action="reinstall",
+ power_status="running",
+ force=True,
+ wait_for_state=False,
+ )
+
+ return resource
+
+ def transform_result(self, resource):
+ if resource:
+ resource["user_data"] = self.get_user_data(resource=resource)
+ return resource
+
+ def absent(self):
+ resource = self.query()
+ if resource and not self.module.check_mode:
+ resource = self.wait_for_state(resource=resource, key="server_status", states=["none", "locked"], cmp="!=")
+
+ return super(AnsibleVultrInstance, self).absent(resource=resource)
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ label=dict(type="str", required=True, aliases=["name"]),
+ hostname=dict(type="str"),
+ app=dict(type="str"),
+ image=dict(type="str"),
+ snapshot=dict(type="str"),
+ os=dict(type="str"),
+ plan=dict(type="str"),
+ activation_email=dict(type="bool", default=False),
+ ddos_protection=dict(type="bool"),
+ backups=dict(type="bool"),
+ enable_ipv6=dict(type="bool"),
+ tags=dict(type="list", elements="str"),
+ vpcs=dict(type="list", elements="str"),
+ reserved_ipv4=dict(type="str"),
+ firewall_group=dict(type="str"),
+ startup_script=dict(type="str"),
+ user_data=dict(type="str"),
+ ssh_keys=dict(type="list", elements="str", no_log=False),
+ region=dict(type="str", required=True),
+ state=dict(
+ choices=[
+ "present",
+ "absent",
+ "started",
+ "stopped",
+ "restarted",
+ "reinstalled",
+ ],
+ default="present",
+ ),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=(("state", "present", ("plan",)),),
+ mutually_exclusive=(("os", "app", "image", "snapshot"),),
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultrInstance(
+ module=module,
+ namespace="vultr_instance",
+ resource_path="/instances",
+ ressource_result_key_singular="instance",
+ resource_create_param_keys=[
+ "label",
+ "hostname",
+ "plan",
+ "app_id",
+ "os_id",
+ "iso_id",
+ "image_id",
+ "snapshot_id",
+ "script_id",
+ "region",
+ "enable_ipv6",
+ "reserved_ipv4",
+ "firewall_group_id",
+ "user_data",
+ "tags",
+ "activation_email",
+ "ddos_protection",
+ "sshkey_id",
+ "backups",
+ "attach_vpc",
+ ],
+ resource_update_param_keys=[
+ "plan",
+ "tags",
+ "firewall_group_id",
+ "enable_ipv6",
+ "ddos_protection",
+ "backups",
+ "user_data",
+ "attach_vpc",
+ "detach_vpc",
+ ],
+ resource_key_name="label",
+ )
+
+ state = module.params.get("state") # type: ignore
+ if state == "absent":
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/instance_info.py b/ansible_collections/vultr/cloud/plugins/modules/instance_info.py
new file mode 100644
index 000000000..2a5c311bb
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/instance_info.py
@@ -0,0 +1,271 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: instance_info
+short_description: Get information about the Vultr instances
+description:
+ - Get infos about available instances.
+version_added: "1.5.0"
+author:
+ - "René Moser (@resmo)"
+options:
+ label:
+ description:
+ - Name of the instance.
+ aliases: [ name ]
+ type: str
+ region:
+ description:
+ - Filter instances by region.
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Get Vultr instance infos of region ams
+ vultr.cloud.instance_info:
+ region: ams
+
+- name: Get Vultr instance infos of a single host
+ vultr.cloud.instance_info:
+ label: myhost
+
+- name: Get all Vultr instance infos
+ vultr.cloud.instance_info:
+ register: results
+
+- name: Print the gathered infos
+ ansible.builtin.debug:
+ var: results.vultr_instance_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_instance_info:
+ description: Response from Vultr API as list.
+ returned: available
+ type: list
+ contains:
+ id:
+ description: ID of the instance.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ v6_main_ip:
+ description: IPv6 of the instance.
+ returned: success
+ type: str
+ sample: ""
+ v6_network:
+ description: IPv6 network of the instance.
+ returned: success
+ type: str
+ sample: ""
+ v6_network_size:
+ description: IPv6 network size of the instance.
+ returned: success
+ type: int
+ sample: 0
+ main_ip:
+ description: IPv4 of the instance.
+ returned: success
+ type: str
+ sample: 95.179.189.95
+ netmask_v4:
+ description: Netmask IPv4 of the instance.
+ returned: success
+ type: str
+ sample: 255.255.254.0
+ hostname:
+ description: Hostname of the instance.
+ returned: success
+ type: str
+ sample: vultr.guest
+ internal_ip:
+ description: Internal IP of the instance.
+ returned: success
+ type: str
+ sample: ""
+ gateway_v4:
+ description: Gateway IPv4.
+ returned: success
+ type: str
+ sample: 95.179.188.1
+ kvm:
+ description: KVM of the instance.
+ returned: success
+ type: str
+ sample: "https://my.vultr.com/subs/vps/novnc/api.php?data=..."
+ disk:
+ description: Disk size of the instance.
+ returned: success
+ type: int
+ sample: 25
+ allowed_bandwidth:
+ description: Allowed bandwidth of the instance.
+ returned: success
+ type: int
+ sample: 1000
+ vcpu_count:
+ description: vCPUs of the instance.
+ returned: success
+ type: int
+ sample: 1
+ firewall_group_id:
+ description: Firewall group ID of the instance.
+ returned: success
+ type: str
+ sample: ""
+ plan:
+ description: Plan of the instance.
+ returned: success
+ type: str
+ sample: vc2-1c-1gb
+ image_id:
+ description: Image ID of the instance.
+ returned: success
+ type: str
+ sample: ""
+ os_id:
+ description: OS ID of the instance.
+ returned: success
+ type: int
+ sample: 186
+ app_id:
+ description: App ID of the instance.
+ returned: success
+ type: int
+ sample: 37
+ date_created:
+ description: Date when the instance was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ label:
+ description: Label of the instance.
+ returned: success
+ type: str
+ sample: my instance
+ region:
+ description: Region the instance was deployed into.
+ returned: success
+ type: str
+ sample: ews
+ status:
+ description: Status about the deployment of the instance.
+ returned: success
+ type: str
+ sample: active
+ server_status:
+ description: Server status of the instance.
+ returned: success
+ type: str
+ sample: installingbooting
+ power_status:
+ description: Power status of the instance.
+ returned: success
+ type: str
+ sample: running
+ ram:
+ description: RAM in MB of the instance.
+ returned: success
+ type: int
+ sample: 1024
+ os:
+ description: OS of the instance.
+ returned: success
+ type: str
+ sample: Application
+ tags:
+ description: Tags of the instance.
+ returned: success
+ type: list
+ sample: [ my-tag ]
+ features:
+ description: Features of the instance.
+ returned: success
+ type: list
+ sample: [ ddos_protection, ipv6, auto_backups ]
+ user_data:
+ description: Base64 encoded user data (cloud init) of the instance.
+ returned: success
+ type: str
+ sample: I2Nsb3VkLWNvbmZpZwpwYWNrYWdlczoKICAtIGh0b3AK
+
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ region=dict(type="str", aliases=["name"]),
+ label=dict(type="str"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_instance_info",
+ resource_path="/instances",
+ ressource_result_key_singular="instance",
+ ressource_result_key_plural="instances",
+ )
+
+ query_params = dict()
+ if module.params["region"] is not None: # type: ignore
+ query_params.update({"region": module.params["region"]}) # type: ignore
+
+ if module.params["label"] is not None: # type: ignore
+ query_params.update({"label": module.params["label"]}) # type: ignore
+
+ vultr.get_result(vultr.query_list(query_params=query_params))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/os_info.py b/ansible_collections/vultr/cloud/plugins/modules/os_info.py
new file mode 100644
index 000000000..8edb7a7f1
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/os_info.py
@@ -0,0 +1,115 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: os_info
+short_description: Get information about the Vultr operation systems
+description:
+ - Get infos about operating systems available to boot servers.
+version_added: "1.0.0"
+author:
+ - "Yanis Guenane (@Spredzy)"
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Get Vultr OSes infos
+ vultr.cloud.os_info:
+ register: results
+
+- name: Print the gathered infos
+ ansible.builtin.debug:
+ var: results.vultr_os_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_os_info:
+ description: Response from Vultr API as list.
+ returned: available
+ type: list
+ contains:
+ arch:
+ description: OS Architecture.
+ returned: success
+ type: str
+ sample: x64
+ family:
+ description: OS family.
+ returned: success
+ type: str
+ sample: openbsd
+ name:
+ description: OS name.
+ returned: success
+ type: str
+ sample: OpenBSD 6 x64
+ windows:
+ description: OS is a MS Windows.
+ returned: success
+ type: bool
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_os_info",
+ resource_path="/os",
+ ressource_result_key_singular="os",
+ ressource_result_key_plural="os",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/plan_info.py b/ansible_collections/vultr/cloud/plugins/modules/plan_info.py
new file mode 100644
index 000000000..639a10731
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/plan_info.py
@@ -0,0 +1,140 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: plan_info
+short_description: Gather information about the Vultr plans
+description:
+ - Gather information about plans available to boot servers.
+version_added: "1.0.0"
+author:
+ - "Yanis Guenane (@Spredzy)"
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Gather Vultr plans information
+ vultr.cloud.plan_info:
+ register: result
+
+- name: Print the gathered information
+ ansible.builtin.debug:
+ var: result.vultr_plan_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_plan_info:
+ description: Response from Vultr API as list.
+ returned: success
+ type: list
+ contains:
+ id:
+ description: ID of the plan.
+ returned: success
+ type: str
+ sample: vhf-8c-32gb
+ vcpu_count:
+ description: Amount of CPUs.
+ returned: success
+ type: int
+ sample: 8
+ ram:
+ description: Amount of RAM in MB.
+ returned: success
+ type: int
+ sample: 32768
+ disk:
+ description: Disk size in GB.
+ returned: success
+ type: int
+ sample: 512
+ disk_count:
+ description: Amount of disks.
+ returned: success
+ type: int
+ sample: 1
+ bandwidth:
+ description: Bandwidth in MB.
+ returned: success
+ type: int
+ sample: 6144
+ monthly_cost:
+ description: Monthly cost in $.
+ returned: success
+ type: int
+ sample: 192
+ type:
+ description: Type of plan.
+ returned: success
+ type: str
+ sample: vhf
+ locations:
+ description: List of locations the plan is available in.
+ returned: success
+ type: list
+ sample: ["ewr"]
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_plan_info",
+ resource_path="/plans",
+ ressource_result_key_singular="plan",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/plan_metal_info.py b/ansible_collections/vultr/cloud/plugins/modules/plan_metal_info.py
new file mode 100644
index 000000000..c7ff478bf
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/plan_metal_info.py
@@ -0,0 +1,153 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2019, Nate River <vitikc@gmail.com>
+# Copyright (c) 2020, Simon Baerlocher <s.baerlocher@sbaerlocher.ch>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: plan_metal_info
+short_description: Gather information about the Vultr bare metal plans
+description:
+ - Gather information about plans available to boot servers.
+version_added: "1.0.0"
+author:
+ - "Nate River (@vitikc)"
+ - "Simon Baerlocher (@sbaerlocher)"
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Gather Vultr bare metal plans information
+ vultr.cloud.plan_metal_info:
+ register: result
+
+- name: Print the gathered information
+ ansible.builtin.debug:
+ var: result.vultr_plan_metal_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_plan_info:
+ description: Response from Vultr API as list.
+ returned: success
+ type: list
+ contains:
+ id:
+ description: ID of the plan.
+ returned: success
+ type: str
+ sample: vbm-4c-32gb
+ cpu_count:
+ description: Amount of CPUs.
+ returned: success
+ type: int
+ sample: 4
+ cpu_threads:
+ description: Amount of CPU threads.
+ returned: success
+ type: int
+ sample: 8
+ cpu_model:
+ description: CPU model.
+ returned: success
+ type: str
+ sample: E3-1270v6
+ ram:
+ description: Amount of RAM in MB.
+ returned: success
+ type: int
+ sample: 32768
+ disk:
+ description: Disk size in GB.
+ returned: success
+ type: int
+ sample: 240
+ disk_count:
+ description: Amount of disks.
+ returned: success
+ type: int
+ sample: 2
+ bandwidth:
+ description: Bandwidth in MB.
+ returned: success
+ type: int
+ sample: 5120
+ monthly_cost:
+ description: Monthly cost in $.
+ returned: success
+ type: int
+ sample: 300
+ type:
+ description: Type of plan.
+ returned: success
+ type: str
+ sample: SSD
+ locations:
+ description: List of locations the plan is available in.
+ returned: success
+ type: list
+ sample: ["ewr"]
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_plan_metal_info",
+ resource_path="/plans-metal",
+ ressource_result_key_singular="plan_metal",
+ ressource_result_key_plural="plans_metal",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/region_info.py b/ansible_collections/vultr/cloud/plugins/modules/region_info.py
new file mode 100644
index 000000000..1e222b9f9
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/region_info.py
@@ -0,0 +1,106 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: region_info
+short_description: Gather information about the Vultr regions
+description:
+ - Gather information about regions available to boot servers.
+version_added: "1.0.0"
+author:
+ - "Yanis Guenane (@Spredzy)"
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Gather Vultr regions information
+ vultr.cloud.region_info:
+ register: result
+
+- name: Print the gathered information
+ ansible.builtin.debug:
+ var: result.vultr_region_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_region_info:
+ description: Response from Vultr API.
+ returned: success
+ type: list
+ sample: [
+ {
+ "block_storage": false,
+ "continent": "Europe",
+ "country": "GB",
+ "ddos_protection": true,
+ "id": 8,
+ "name": "London",
+ "regioncode": "LHR",
+ "state": ""
+ }
+ ]
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_region_info",
+ resource_path="/regions",
+ ressource_result_key_singular="region",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/reserved_ip.py b/ansible_collections/vultr/cloud/plugins/modules/reserved_ip.py
new file mode 100644
index 000000000..9bc2e254b
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/reserved_ip.py
@@ -0,0 +1,290 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: reserved_ip
+short_description: Manages reserved IPs on Vultr
+description:
+ - Create, attach, detach and remove reserved IPs.
+version_added: "1.0.0"
+author:
+ - "René Moser (@resmo)"
+options:
+ label:
+ description:
+ - Label of the reserved IP.
+ required: true
+ aliases: [ name ]
+ type: str
+ instance_name:
+ description:
+ - Name of the Instance the reserved IP should be attached to.
+ - Mutually exclusive with I(instance_id).
+ type: str
+ instance_id:
+ description:
+ - ID of the Instance the reserved IP should be attached to.
+ - Mutually exclusive with I(instance_name).
+ type: str
+ region:
+ description:
+ - Region of the reserved IP will be related to.
+ type: str
+ required: true
+ ip_type:
+ description:
+ - Type of the IP.
+ type: str
+ choices: [ v4, v6 ]
+ required: true
+ state:
+ description:
+ - State of the reserved IP.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Ensure a reserved IP present and attached to an instance
+ vultr.cloud.reserved_ip:
+ label: my attached IP
+ region: ewr
+ ip_type: v4
+ instance_name: web-01
+
+- name: Ensure a reserved IP is detached
+ vultr.cloud.reserved_ip:
+ label: my reserved IP
+ region: ewr
+ ip_type: v4
+ instance_id: ""
+
+- name: Ensure a reserved IP is absent
+ vultr.cloud.reserved_ip:
+ label: my attached IP
+ region: ewr
+ ip_type: v4
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_reserved_ip:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: ID of the reserved IP.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ label:
+ description: Name of the reserved IP.
+ returned: success
+ type: str
+ sample: example.com
+ region:
+ description: Region of the reserved IP is related to.
+ returned: success
+ type: str
+ sample: ewr
+ ip_type:
+ description: Type of the reserved IP.
+ returned: success
+ type: str
+ sample: v4
+ subnet:
+ description: Subnet of the reserved IP.
+ returned: success
+ type: str
+ sample: v4
+ subnet_size:
+ description: Size of the subnet of the reserved IP.
+ returned: success
+ type: int
+ sample: 32
+ instance_id:
+ description: ID of the Instance the reserved IP is attached to.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b
+"""
+
+import urllib
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+class AnsibleVultrReservedIp(AnsibleVultr):
+ def configure(self):
+ self.instance_id = self.get_instance_id()
+
+ def get_instance_id(self):
+ instance_id = self.module.params["instance_id"]
+ if instance_id is not None:
+ return instance_id
+
+ instance_name = self.module.params["instance_name"]
+ if instance_name is not None:
+
+ # Empty string ID means detach instance
+ if len(instance_name) == 0:
+ return ""
+
+ # URL encode label
+ try:
+ label = urllib.quote(instance_name) # type: ignore
+ except AttributeError:
+ label = urllib.parse.quote(instance_name) # type: ignore
+
+ # Filter instances by label
+ resources = self.api_query(path="/instances?label=%s" % label) or dict()
+ if not resources or not resources["instances"]:
+ self.module.fail_json(msg="No instance with name found: %s" % instance_name)
+
+ if len(resources["instances"]) > 1:
+ self.module.fail_json(msg="More then one instance with name found: %s" % instance_name)
+
+ return resources["instances"][0]["id"]
+
+ def query_list(self, path=None, result_key=None):
+ resources = self.api_query(path=self.resource_path) or dict()
+
+ resources_filtered = list()
+ for resource in resources[self.ressource_result_key_plural]:
+ # Skip IP with different type
+ if resource["ip_type"] != self.module.params["ip_type"]:
+ continue
+ # Skip IP in different region
+ if resource["region"] != self.module.params["region"]:
+ continue
+ resources_filtered.append(resource)
+
+ return resources_filtered
+
+ def create(self):
+ resource = super().create() or dict()
+ if resource and self.instance_id:
+ if not self.module.check_mode:
+ # Attach instance
+ self.api_query(
+ path="%s/%s/%s"
+ % (
+ self.resource_path,
+ resource[self.resource_key_id],
+ "attach",
+ ),
+ method="POST",
+ data=dict(instance_id=self.instance_id),
+ )
+ # Refresh
+ resource = self.query_by_id(resource_id=resource[self.resource_key_id])
+ return resource
+
+ def update(self, resource):
+ if self.instance_id is None:
+ return resource
+
+ # Detach instance
+ elif resource["instance_id"] and not self.instance_id:
+ self.result["changed"] = True
+ if not self.module.check_mode:
+ self.api_query(
+ path="%s/%s/%s" % (self.resource_path, resource[self.resource_key_id], "detach"),
+ method="POST",
+ data=dict(instance_id=self.instance_id),
+ )
+ # Refresh
+ resource = self.query_by_id(resource_id=resource[self.resource_key_id])
+
+ # Attach instance or change attached instance
+ elif self.instance_id and resource["instance_id"] != self.instance_id:
+ self.result["changed"] = True
+ if not self.module.check_mode:
+ self.api_query(
+ path="%s/%s/%s" % (self.resource_path, resource[self.resource_key_id], "attach"),
+ method="POST",
+ data=dict(instance_id=self.instance_id),
+ )
+ # Refresh
+ resource = self.query_by_id(resource_id=resource[self.resource_key_id])
+
+ return resource
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ label=dict(type="str", required=True, aliases=["name"]),
+ instance_id=dict(type="str"),
+ instance_name=dict(type="str"),
+ ip_type=dict(type="str", required=True, choices=["v4", "v6"]),
+ region=dict(type="str", required=True),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=(["instance_id", "instance_name"],),
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultrReservedIp(
+ module=module,
+ namespace="vultr_reserved_ip",
+ resource_path="/reserved-ips",
+ ressource_result_key_singular="reserved_ip",
+ resource_create_param_keys=["region", "ip_type", "label"],
+ resource_key_name="label",
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/snapshot.py b/ansible_collections/vultr/cloud/plugins/modules/snapshot.py
new file mode 100644
index 000000000..9dba03c74
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/snapshot.py
@@ -0,0 +1,218 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2023, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: snapshot
+short_description: Manages snapshots on Vultr
+description:
+ - Create and remove snapshots.
+version_added: "1.7.0"
+author: "René Moser (@resmo)"
+options:
+ description:
+ description:
+ - Description of the snapshot.
+ required: true
+ aliases: [ name ]
+ type: str
+ instance:
+ description:
+ - The description or ID of the instance from which to take the snapshot.
+ - Mutually exclusive with I(url).
+ - I(instance) or I(url) is required if I(state=present).
+ type: str
+ url:
+ description:
+ - The URL of the snapshot image (RAW) to be uploaded.
+ - Mutually exclusive with I(instance).
+ - I(instance) or I(url) is required if I(state=present).
+ type: str
+ state:
+ description:
+ - State of the snapshot.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Ensure a snapshot is present
+ vultr.cloud.snapshot:
+ description: my snapshot of my instance
+ instance: my instance
+
+- name: Ensure a snapshot is present
+ vultr.cloud.snapshot:
+ description: debian 11 generic
+ url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.raw
+
+- name: Ensure a snapshot is absent
+ vultr.cloud.snapshot:
+ description: my snapshot of my instance
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_snapshot:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: ID of the snapshot.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ description:
+ description: Description of the snapshot.
+ returned: success
+ type: str
+ sample: my vpc
+ date_created:
+ description: Date the snapshot was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ size:
+ description: Size of the snapshot.
+ returned: success
+ type: int
+ sample: 42949672960
+ compressed_size:
+ description: Compressed size of the snapshot.
+ returned: success
+ type: int
+ sample: 949678560
+ status:
+ description: Status of the snapshot.
+ returned: success
+ type: str
+ sample: complete
+ os_id:
+ description: ID of the OS.
+ returned: success
+ type: int
+ sample: 215
+ app_id:
+ description: ID of the app.
+ returned: success
+ type: int
+ sample: 0
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+class AnsibleVultrSnapshot(AnsibleVultr):
+ def get_instance(self):
+ return self.query_filter_list_by_name(
+ key_name="label",
+ param_key="instance",
+ path="/instances",
+ result_key="instances",
+ fail_not_found=True,
+ )
+
+ def create(self):
+ param_keys = ("url", "instance")
+ if not any(self.module.params.get(x) is not None for x in param_keys):
+ self.module.fail_json(msg="missing required arguements, one of the following required: %s" % ", ".join(param_keys))
+
+ if self.module.params.get("url") is not None:
+ self.resource_create_param_keys.append("url")
+ # Upload by URL has a different endpoint
+ self.resource_path = self.resource_path + "/create-from-url"
+ else:
+ self.module.params["instance_id"] = self.get_instance()["id"]
+ self.resource_create_param_keys.append("instance_id")
+
+ resource = super(AnsibleVultrSnapshot, self).create()
+
+ # Reset endpoint
+ self.resource_path = "/snapshots"
+
+ if resource:
+ resource = self.wait_for_state(resource=resource, key="status", states=["complete"])
+
+ return resource
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ description=dict(type="str", required=True, aliases=["name"]),
+ instance=dict(type="str"),
+ url=dict(type="str"),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=(("instance", "url"),),
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultrSnapshot(
+ module=module,
+ namespace="vultr_snapshot",
+ resource_path="/snapshots",
+ ressource_result_key_singular="snapshot",
+ resource_create_param_keys=[
+ "description",
+ ],
+ resource_update_param_keys=[
+ "description",
+ ],
+ resource_key_name="description",
+ resource_update_method="PUT",
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/snapshot_info.py b/ansible_collections/vultr/cloud/plugins/modules/snapshot_info.py
new file mode 100644
index 000000000..38fa4b85e
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/snapshot_info.py
@@ -0,0 +1,132 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2023, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: snapshot_info
+short_description: Gather information about the Vultr snapshots
+description:
+ - Gather information about snapshots available.
+version_added: "1.7.0"
+author:
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Gather Vultr snapshots information
+ vultr.cloud.snapshot_info:
+ register: result
+
+- name: Print the gathered information
+ ansible.builtin.debug:
+ var: result.vultr_snapshot_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_snapshot_info:
+ description: Response from Vultr API as list.
+ returned: success
+ type: list
+ contains:
+ id:
+ description: ID of the snapshot.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ description:
+ description: Description of the snapshot.
+ returned: success
+ type: str
+ sample: my vpc
+ date_created:
+ description: Date the snapshot was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ size:
+ description: Size of the snapshot.
+ returned: success
+ type: int
+ sample: 42949672960
+ compressed_size:
+ description: Compressed size of the snapshot.
+ returned: success
+ type: int
+ sample: 949678560
+ status:
+ description: Status of the snapshot.
+ returned: success
+ type: str
+ sample: complete
+ os_id:
+ description: ID of the OS.
+ returned: success
+ type: int
+ sample: 215
+ app_id:
+ description: ID of the app.
+ returned: success
+ type: int
+ sample: 0
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_snapshot_info",
+ resource_path="/snapshots",
+ ressource_result_key_singular="snapshot",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/ssh_key.py b/ansible_collections/vultr/cloud/plugins/modules/ssh_key.py
new file mode 100644
index 000000000..2c85eebff
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/ssh_key.py
@@ -0,0 +1,148 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: ssh_key
+short_description: Manages ssh keys on Vultr.
+description:
+ - Create, update and remove ssh keys.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+options:
+ name:
+ description:
+ - Name of the ssh key.
+ required: true
+ type: str
+ ssh_key:
+ description:
+ - SSH public key.
+ - Required if C(state=present).
+ type: str
+ state:
+ description:
+ - State of the ssh key.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+
+"""
+
+EXAMPLES = """
+- name: ensure an SSH key is present
+ vultr.cloud.ssh_key:
+ name: my ssh key
+ ssh_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
+
+- name: ensure an SSH key is absent
+ vultr.cloud.ssh_key:
+ name: my ssh key
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_ssh_key:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: ID of the ssh key.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ name:
+ description: Name of the ssh key.
+ returned: success
+ type: str
+ sample: my ssh key
+ date_created:
+ description: Date the ssh key was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ ssh_key:
+ description: SSH public key.
+ returned: success
+ type: str
+ sample: ssh-rsa AA... someother@example.com
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ name=dict(type="str", required=True),
+ ssh_key=dict(type="str", no_log=False),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=[
+ ("state", "present", ["ssh_key"]),
+ ],
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_ssh_key",
+ resource_path="/ssh-keys",
+ ressource_result_key_singular="ssh_key",
+ resource_create_param_keys=["name", "ssh_key"],
+ resource_update_param_keys=["name", "ssh_key"],
+ resource_key_name="name",
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/ssh_key_info.py b/ansible_collections/vultr/cloud/plugins/modules/ssh_key_info.py
new file mode 100644
index 000000000..24441885b
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/ssh_key_info.py
@@ -0,0 +1,117 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: ssh_key_info
+short_description: Get information about the Vultr SSH keys
+description:
+ - Get infos about SSH keys available.
+version_added: "1.0.0"
+author:
+ - "Yanis Guenane (@Spredzy)"
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+
+"""
+
+EXAMPLES = """
+- name: Get Vultr SSH keys infos
+ vultr.cloud.ssh_key_info:
+ register: result
+
+- name: Print the infos
+ ansible.builtin.debug:
+ var: result.vultr_ssh_key_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_ssh_key_info:
+ description: Response from Vultr API as list.
+ returned: success
+ type: list
+ contains:
+ id:
+ description: ID of the ssh key.
+ returned: success
+ type: str
+ sample: 7d726ffe-9be2-4f88-8cda-fa7eba1da2b5
+ name:
+ description: Name of the ssh key.
+ returned: success
+ type: str
+ sample: my ssh key
+ date_created:
+ description: Date the ssh key was created.
+ returned: success
+ type: str
+ sample: "2021-11-07T05:57:59-05:00"
+ ssh_key:
+ description: SSH public key.
+ returned: success
+ type: str
+ sample: "ssh-rsa AA... someother@example.com"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_ssh_key_info",
+ resource_path="/ssh-keys",
+ ressource_result_key_singular="ssh_key",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/startup_script.py b/ansible_collections/vultr/cloud/plugins/modules/startup_script.py
new file mode 100644
index 000000000..4211b1aba
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/startup_script.py
@@ -0,0 +1,196 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: startup_script
+short_description: Manages startup scripts on Vultr
+description:
+ - Create, update and remove startup scripts.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+options:
+ name:
+ description:
+ - The script name.
+ required: true
+ type: str
+ type:
+ description:
+ - The script type, can not be changed once created.
+ default: boot
+ choices: [ boot, pxe ]
+ aliases: [ script_type ]
+ type: str
+ script:
+ description:
+ - The script source code.
+ - Required if I(state=present).
+ type: str
+ state:
+ description:
+ - State of the script.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: ensure a pxe script exists, source from a file
+ vultr.cloud.startup_script:
+ name: my_web_script
+ script_type: pxe
+ script: "{{ lookup('file', 'path/to/script') }}"
+
+- name: ensure a boot script exists
+ vultr.cloud.startup_script:
+ name: vultr_startup_script
+ script: "#!/bin/bash\necho Hello World > /root/hello"
+
+- name: ensure a script is absent
+ vultr.cloud.startup_script:
+ name: my_web_script
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_startup_script:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: ID of the startup script.
+ returned: success
+ type: str
+ sample: 7d726ffe-9be2-4f88-8cda-fa7eba1da2b5
+ name:
+ description: Name of the startup script.
+ returned: success
+ type: str
+ sample: my startup script
+ script:
+ description: The source code of the startup script.
+ returned: success
+ type: str
+ sample: "#!/bin/bash\necho Hello World > /root/hello"
+ type:
+ description: The type of the startup script.
+ returned: success
+ type: str
+ sample: pxe
+ date_created:
+ description: Date the startup script was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ date_modified:
+ description: Date the startup script was modified.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+"""
+
+import base64
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+class AnsibleVultrStartupScript(AnsibleVultr):
+ def configure(self):
+ if self.module.params["script"]:
+ self.module.params["script"] = base64.b64encode(self.module.params["script"].encode())
+
+ def update(self, resource):
+ resource["script"] = resource["script"].encode()
+ return super(AnsibleVultrStartupScript, self).update(resource=resource)
+
+ def transform_result(self, resource):
+ if resource:
+ resource["script"] = base64.b64decode(resource["script"]).decode()
+ return resource
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ name=dict(type="str", required=True),
+ script=dict(
+ type="str",
+ ),
+ type=dict(
+ type="str",
+ default="boot",
+ choices=["boot", "pxe"],
+ aliases=["script_type"],
+ ),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=[
+ ("state", "present", ["script"]),
+ ],
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultrStartupScript(
+ module=module,
+ namespace="vultr_startup_script",
+ resource_path="/startup-scripts",
+ ressource_result_key_singular="startup_script",
+ resource_get_details=True,
+ resource_create_param_keys=["name", "type", "script"],
+ resource_update_param_keys=["name", "script"],
+ resource_key_name="name",
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/startup_script_info.py b/ansible_collections/vultr/cloud/plugins/modules/startup_script_info.py
new file mode 100644
index 000000000..dd91166aa
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/startup_script_info.py
@@ -0,0 +1,120 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: startup_script_info
+short_description: Gather information about the Vultr startup scripts
+description:
+ - Gather information about startup scripts available.
+version_added: "1.0.0"
+author:
+ - "Yanis Guenane (@Spredzy)"
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Gather Vultr startup scripts information
+ vultr.cloud.startup_script_info:
+ register: result
+
+- name: Print the gathered information
+ ansible.builtin.debug:
+ var: result.vultr_startup_script_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_startup_script_info:
+ description: Response from Vultr API.
+ returned: success
+ type: list
+ contains:
+ id:
+ description: ID of the startup script.
+ returned: success
+ type: str
+ sample: 56e5b8b5-120c-40b1-a087-3abc9cd8df57
+ name:
+ description: Name of the startup script.
+ returned: success
+ type: str
+ sample: my startup script
+ type:
+ description: The type of the startup script.
+ returned: success
+ type: str
+ sample: pxe
+ date_created:
+ description: Date the startup script was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ date_modified:
+ description: Date the startup script was modified.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_startup_script_info",
+ resource_path="/startup-scripts",
+ ressource_result_key_singular="startup_script",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/user.py b/ansible_collections/vultr/cloud/plugins/modules/user.py
new file mode 100644
index 000000000..dd5124345
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/user.py
@@ -0,0 +1,229 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: user
+short_description: Manages users on Vultr
+description:
+ - Create, update and remove users.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+options:
+ name:
+ description:
+ - Name of the user
+ required: true
+ type: str
+ email:
+ description:
+ - Email of the user.
+ - Required if C(state=present).
+ type: str
+ password:
+ description:
+ - Password of the user.
+ - Only considered while creating a user or when C(force=true).
+ type: str
+ force:
+ description:
+ - Password will only be changed with enforcement.
+ default: false
+ type: bool
+ api_enabled:
+ description:
+ - Whether the API is enabled or not.
+ default: true
+ type: bool
+ acls:
+ description:
+ - List of ACLs this users should have.
+ - Required if C(state=present).
+ - One or more of the choices list, some depend on each other.
+ choices:
+ - manage_users
+ - subscriptions_view
+ - subscriptions
+ - provisioning
+ - billing
+ - support
+ - abuse
+ - dns
+ - upgrade
+ - objstore
+ - loadbalancer
+ aliases: [ acl ]
+ type: list
+ elements: str
+ state:
+ description:
+ - State of the user.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Ensure a user exists
+ vultr.cloud.user:
+ name: john
+ email: john.doe@example.com
+ password: s3cr3t
+ acls:
+ - manage_users
+ - subscriptions
+
+- name: Remove a user
+ vultr.cloud.user:
+ name: john
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_user:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: ID of the user.
+ returned: success
+ type: str
+ sample: 7d726ffe-9be2-4f88-8cda-fa7eba1da2b5
+ api_key:
+ description: API key of the user.
+ returned: only after resource was created
+ type: str
+ sample: 567E6K567E6K567E6K567E6K567E6K
+ name:
+ description: Name of the user.
+ returned: success
+ type: str
+ sample: john
+ email:
+ description: Email of the user.
+ returned: success
+ type: str
+ sample: "john@example.com"
+ api_enabled:
+ description: Whether the API is enabled or not.
+ returned: success
+ type: bool
+ sample: true
+ acls:
+ description: List of ACLs of the user.
+ returned: success
+ type: list
+ sample: [manage_users, support, upgrade]
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+ACLS = [
+ "manage_users",
+ "subscriptions_view",
+ "subscriptions",
+ "provisioning",
+ "billing",
+ "support",
+ "abuse",
+ "dns",
+ "upgrade",
+ "objstore",
+ "loadbalancer",
+]
+
+
+class AnsibleVultrUser(AnsibleVultr):
+ def create(self):
+ # Password is required in create mode.
+ self.module.fail_on_missing_params(required_params=["password"])
+ return super(AnsibleVultrUser, self).create()
+
+ def update(self, resource):
+ # Password is never returned and we can not compare.
+ # That is why we update it only if forced
+ force = self.module.params.get("force")
+ if force:
+ self.resource_update_param_keys.append("password")
+ return super(AnsibleVultrUser, self).update(resource=resource)
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ name=dict(type="str", required=True),
+ email=dict(type="str"),
+ password=dict(type="str", no_log=True),
+ force=dict(type="bool", default=False),
+ api_enabled=dict(type="bool", default=True),
+ acls=dict(type="list", elements="str", choices=ACLS, aliases=["acl"]),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=[
+ ("state", "present", ["email", "acls"]),
+ ],
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultrUser(
+ module=module,
+ namespace="vultr_user",
+ resource_path="/users",
+ ressource_result_key_singular="user",
+ resource_create_param_keys=["name", "email", "password", "api_enabled", "acls"],
+ resource_update_param_keys=["name", "email", "api_enabled", "acls"],
+ resource_key_name="name",
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/user_info.py b/ansible_collections/vultr/cloud/plugins/modules/user_info.py
new file mode 100644
index 000000000..5d0a61efe
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/user_info.py
@@ -0,0 +1,125 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: user_info
+short_description: Get information about the Vultr users
+version_added: "1.0.0"
+description:
+ - Get infos about users available.
+author:
+ - "Yanis Guenane (@Spredzy)"
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Get Vultr user infos
+ vultr.cloud.user_info:
+ register: result
+
+- name: Print the infos
+ ansible.builtin.debug:
+ var: result.vultr_user_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_user_info:
+ description: Response from Vultr API as list.
+ returned: available
+ type: list
+ contains:
+ id:
+ description: ID of the user.
+ returned: success
+ type: str
+ sample: 7d726ffe-9be2-4f88-8cda-fa7eba1da2b5
+ api_key:
+ description: API key of the user.
+ returned: only after resource was created
+ type: str
+ sample: 567E6K567E6K567E6K567E6K567E6K
+ name:
+ description: Name of the user.
+ returned: success
+ type: str
+ sample: john
+ email:
+ description: Email of the user.
+ returned: success
+ type: str
+ sample: "john@example.com"
+ api_enabled:
+ description: Whether the API is enabled or not.
+ returned: success
+ type: bool
+ sample: true
+ acls:
+ description: List of ACLs of the user.
+ returned: success
+ type: list
+ sample: [ manage_users, support, upgrade ]
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_user_info",
+ resource_path="/users",
+ ressource_result_key_singular="user",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/vpc.py b/ansible_collections/vultr/cloud/plugins/modules/vpc.py
new file mode 100644
index 000000000..83a183c8d
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/vpc.py
@@ -0,0 +1,182 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: vpc
+short_description: Manages VPCs on Vultr
+description:
+ - Create and remove VPCs.
+version_added: "1.0.0"
+author: "René Moser (@resmo)"
+options:
+ description:
+ description:
+ - Description of the VPC.
+ required: true
+ aliases: [ name ]
+ type: str
+ v4_subnet:
+ description:
+ - IPv4 subnet of the VPC.
+ - Required if I(state=present).
+ type: str
+ v4_subnet_mask:
+ description:
+ - IPv4 subnet mask of the VPC.
+ - Required if I(state=present).
+ type: int
+ region:
+ description:
+ - Region the VPC will be related to.
+ - Required if I(state=present).
+ type: str
+ state:
+ description:
+ - State of the VPC.
+ default: present
+ choices: [ present, absent ]
+ type: str
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Ensure a VPC is present
+ vultr.cloud.vpc:
+ description: my VPC.
+ subnet: 10.99.1.0
+ subnet_mask: 24
+ region: ewr
+
+- name: Ensure a VPC is absent
+ vultr.cloud.vpc:
+ description: my VPC.
+ state: absent
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_vpc:
+ description: Response from Vultr API.
+ returned: success
+ type: dict
+ contains:
+ id:
+ description: ID of the VPC.
+ returned: success
+ type: str
+ sample: cb676a46-66fd-4dfb-b839-443f2e6c0b60
+ description:
+ description: Description of the VPC.
+ returned: success
+ type: str
+ sample: my vpc
+ v4_subnet:
+ description: Subnet of the VPC.
+ returned: success
+ type: str
+ sample: 10.99.1.0
+ v4_subnet_maks:
+ description: Subnet mask of the VPC.
+ returned: success
+ type: str
+ sample: 10.99.1.0
+ date_created:
+ description: Date the VPC was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ date_modified:
+ description: Date the VPC was modified.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+ argument_spec.update(
+ dict(
+ description=dict(type="str", required=True, aliases=["name"]),
+ v4_subnet=dict(type="str"),
+ v4_subnet_mask=dict(type="int"),
+ region=dict(type="str"),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ ) # type: ignore
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=(
+ (
+ "state",
+ "present",
+ ("v4_subnet", "v4_subnet_mask", "region"),
+ ),
+ ),
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_vpc",
+ resource_path="/vpcs",
+ ressource_result_key_singular="vpc",
+ resource_create_param_keys=[
+ "description",
+ "v4_subnet",
+ "v4_subnet_mask",
+ "region",
+ ],
+ resource_update_param_keys=["description"],
+ resource_key_name="description",
+ resource_update_method="PUT",
+ )
+
+ if module.params.get("state") == "absent": # type: ignore
+ vultr.absent()
+ else:
+ vultr.present()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/plugins/modules/vpc_info.py b/ansible_collections/vultr/cloud/plugins/modules/vpc_info.py
new file mode 100644
index 000000000..5dc67a529
--- /dev/null
+++ b/ansible_collections/vultr/cloud/plugins/modules/vpc_info.py
@@ -0,0 +1,122 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: vpc_info
+short_description: Gather information about the Vultr VPCs
+description:
+ - Gather information about VPCs available.
+version_added: "1.0.0"
+author:
+ - "René Moser (@resmo)"
+extends_documentation_fragment:
+ - vultr.cloud.vultr_v2
+"""
+
+EXAMPLES = """
+- name: Gather Vultr VPCs information
+ vultr.cloud.vpc_info:
+ register: result
+
+- name: Print the gathered information
+ ansible.builtin.debug:
+ var: result.vultr_vpc_info
+"""
+
+RETURN = """
+---
+vultr_api:
+ description: Response from Vultr API with a few additions/modification.
+ returned: success
+ type: dict
+ contains:
+ api_timeout:
+ description: Timeout used for the API requests.
+ returned: success
+ type: int
+ sample: 60
+ api_retries:
+ description: Amount of max retries for the API requests.
+ returned: success
+ type: int
+ sample: 5
+ api_retry_max_delay:
+ description: Exponential backoff delay in seconds between retries up to this max delay value.
+ returned: success
+ type: int
+ sample: 12
+ api_endpoint:
+ description: Endpoint used for the API requests.
+ returned: success
+ type: str
+ sample: "https://api.vultr.com/v2"
+vultr_vpc_info:
+ description: Response from Vultr API as list.
+ returned: success
+ type: list
+ contains:
+ id:
+ description: ID of the VPC.
+ returned: success
+ type: str
+ sample: "cb676a46-66fd-4dfb-b839-443f2e6c0b60"
+ description:
+ description: Description of the VPC.
+ returned: success
+ type: str
+ sample: myvpc
+ date_created:
+ description: Date when the VPC was created.
+ returned: success
+ type: str
+ sample: "2020-10-10T01:56:20+00:00"
+ region:
+ description: Region the VPC was deployed into.
+ returned: success
+ type: str
+ sample: ewr
+ v4_subnet:
+ description: IPv4 Network address
+ returned: success
+ type: str
+ sample: 192.168.42.0
+ v4_subnet_mask:
+ description: Ipv4 Network mask
+ returned: success
+ type: int
+ sample: 24
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ..module_utils.vultr_v2 import AnsibleVultr, vultr_argument_spec
+
+
+def main():
+ argument_spec = vultr_argument_spec()
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ vultr = AnsibleVultr(
+ module=module,
+ namespace="vultr_vpc_info",
+ resource_path="/vpcs",
+ ressource_result_key_singular="vpc",
+ )
+
+ vultr.get_result(vultr.query_list())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/vultr/cloud/tests/integration/cloud-config-vultr.ini.template b/ansible_collections/vultr/cloud/tests/integration/cloud-config-vultr.ini.template
new file mode 100644
index 000000000..bdd336278
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/cloud-config-vultr.ini.template
@@ -0,0 +1,12 @@
+# This is the configuration template for ansible-test Vultr integration tests.
+#
+# You do not need this template if you are:
+#
+# 1) Running integration tests without using ansible-test.
+#
+# If you want to test against the Vultr public API,
+# fill in the values below and save this file without the .template extension.
+# This will cause ansible-test to use the given configuration.
+
+[default]
+key = ...
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/account_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/account_info/aliases
new file mode 100644
index 000000000..1e9555644
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/account_info/aliases
@@ -0,0 +1,2 @@
+cloud/vultr
+smoke/vultr
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/account_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/account_info/tasks/main.yml
new file mode 100644
index 000000000..51f4d0ed9
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/account_info/tasks/main.yml
@@ -0,0 +1,27 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test get vultr account infos in check mode
+ vultr.cloud.account_info:
+ check_mode: true
+ register: result
+
+- name: verify test get vultr account infos in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_account_info.balance is defined
+ - result.vultr_account_info.last_payment_amount is defined
+ - result.vultr_account_info.last_payment_date is defined
+ - result.vultr_account_info.last_payment_amount is defined
+
+- name: test get vultr account fact
+ vultr.cloud.account_info:
+ register: result
+
+- name: verify test get vultr account infos
+ ansible.builtin.assert:
+ that:
+ - result.vultr_account_info.balance is defined
+ - result.vultr_account_info.last_payment_amount is defined
+ - result.vultr_account_info.last_payment_date is defined
+ - result.vultr_account_info.last_payment_amount is defined
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/defaults/main.yml
new file mode 100644
index 000000000..b47b70cda
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/defaults/main.yml
@@ -0,0 +1,16 @@
+---
+vultr_block_storage_name: "{{ vultr_resource_prefix }}-volume"
+vultr_block_storage_size: 10
+vultr_block_storage_size_2: 12
+vultr_block_storage_size_3: 14
+
+vultr_block_storage_region: ewr
+
+vultr_block_storage_block_type: high_perf
+
+vultr_instance_name: "{{ vultr_resource_prefix }}_vm_for_attachment"
+vultr_instance_ssh_keys:
+ - name: "{{ vultr_resource_prefix }}_key1"
+ key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAyWYItY+3w5b8PdGRoz0oY5mufqydW96naE+VM3JSvJFAUS08rAjQQpQ03ymoALeHQy6JVZbcgecxn6p0pAOINQdqufn4udPtOPCtMjNiPGpkSM9ah/6X5+kvyWMNrvlf+Ld4OOoszP5sAkgQzIbrFQAm41XknBUha0zkewZwfrVhain4pnDjV7wCcChId/Q/Gbi4xMtXkisznWcAJcueBs3EEZDKhJ5q0VeWSJEhYJDLFN1sOxF0AIUnMrOhfKQ/LjgREXPB6uCl899INUTXRNNjRpeMXyJ2wMMmOAbua2qEd1r13Bu1n+6A823Hzb33fyMXuqWnJwBJ4DCvMlGuEsfuOK+xk7DaBfLHbcM6fsPk0/4psTE6YLgC41remr6+u5ZWsY/faMtSnNPie8Z8Ov0DIYGdhbJjUXk1HomxRV9+ZfZ2Ob8iCwlaAQAyEUM6fs3Kxt8pBD8dx1HOkhsfBWPvuDr5y+kqE7H8/MuPDTc0QgH2pjUMpmw/XBwNDHshVEjrZvtICOjOLUJxcowLO1ivNYwPwowQxfisMy56LfYdjsOslBiqsrkAqvNGm1zu8wKHeqVN9w5l3yUELpvubfm9NKIvYcl6yWF36T0c5vE+g0DU/Jy4XpTj0hZG9QV2mRQcLJnd2pxQtJT7cPFtrn/+tgRxzjEtbDXummDV4sE= mail@renemoser.net"
+
+vultr_instance_plan: vc2-1c-1gb
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/failures.yml b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/failures.yml
new file mode 100644
index 000000000..e588b0401
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/failures.yml
@@ -0,0 +1,21 @@
+---
+- name: test fail if missing label
+ vultr.cloud.block_storage:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing label
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: label"'
+
+- name: test fail if missing params for state=present
+ vultr.cloud.block_storage:
+ name: "{{ vultr_block_storage_name }}"
+ register: result
+ ignore_errors: true
+- name: verify fail if missing params for state=present
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "state is present but all of the following are missing: size_gb, region"'
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/main.yml
new file mode 100644
index 000000000..a6b410965
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/main.yml
@@ -0,0 +1,16 @@
+---
+- block:
+ - ansible.builtin.import_tasks: failures.yml
+ - ansible.builtin.import_tasks: tests.yml
+ # TODO: make test more reliable
+ # - ansible.builtin.import_tasks: tests_attach_to_server.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_instance
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_ssh_key
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_block_storage
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/tests.yml
new file mode 100644
index 000000000..ea1de2439
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/tests.yml
@@ -0,0 +1,165 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup ensure volume absent
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ state: absent
+
+- name: test create block storage volume in check mode
+ vultr.cloud.block_storage:
+ name: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ register: result
+ check_mode: true
+- name: verify test create block storage volume in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create block storage volume
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ register: result
+- name: verify test create block storage volume
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_block_storage.label == vultr_block_storage_name
+ - result.vultr_block_storage.region == vultr_block_storage_region
+ - result.vultr_block_storage.size_gb == 10
+ - result.vultr_block_storage.block_type == vultr_block_storage_block_type
+
+- name: test create block storage volume idempotence
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ register: result
+- name: verify test create block storage volume idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_block_storage.label == vultr_block_storage_name
+ - result.vultr_block_storage.region == vultr_block_storage_region
+ - result.vultr_block_storage.size_gb == vultr_block_storage_size
+ - result.vultr_block_storage.block_type == vultr_block_storage_block_type
+
+- name: test shrink block storage ignored
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size - 1 }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ register: result
+- name: verify test shrink block storage ignored
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_block_storage.label == vultr_block_storage_name
+ - result.vultr_block_storage.region == vultr_block_storage_region
+ - result.vultr_block_storage.size_gb == vultr_block_storage_size
+ - result.vultr_block_storage.block_type == vultr_block_storage_block_type
+
+# volumes size can only be modified every 60s
+- name: wait about 60s before resizing volume
+ wait_for:
+ timeout: 61
+
+- name: test resize block storage volume in check mode
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size_2 }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ register: result
+ check_mode: true
+- name: verify test resize block storage volume in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_block_storage.size_gb == vultr_block_storage_size
+
+- name: test resize block storage volume
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size_2 }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ register: result
+- name: verify test resize block storage volume
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_block_storage.size_gb == vultr_block_storage_size_2
+
+- name: test resize block storage volume idempotency
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size_2 }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ register: result
+- name: verify test resize block storage volume idempotency
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_block_storage.size_gb == vultr_block_storage_size_2
+
+- name: wait about 60s before resizing volume
+ wait_for:
+ timeout: 61
+
+- name: test shrinking warning block storage volume
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ register: result
+- name: verify test shrinking warning block storage volume
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_block_storage.size_gb == vultr_block_storage_size_2
+
+- name: test destroy block storage volume in check mode
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ state: absent
+ check_mode: true
+ register: result
+- name: verify test destroy block storage volume in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_block_storage.label == vultr_block_storage_name
+ - result.vultr_block_storage.block_type == vultr_block_storage_block_type
+
+- name: test destroy block storage volume
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ state: absent
+ register: result
+- name: verify test destroy block storage volume
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_block_storage.label == vultr_block_storage_name
+ - result.vultr_block_storage.block_type == vultr_block_storage_block_type
+
+- name: test destroy block storage volume idempotence
+ vultr.cloud.block_storage:
+ name: "{{ vultr_block_storage_name }}"
+ state: absent
+ register: result
+- name: verify test destroy block storage volume idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/tests_attach_to_server.yml b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/tests_attach_to_server.yml
new file mode 100644
index 000000000..efb0ab558
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage/tasks/tests_attach_to_server.yml
@@ -0,0 +1,151 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup create ssh keys
+ vultr.cloud.ssh_key:
+ name: "{{ item.name }}"
+ ssh_key: "{{ item.key }}"
+ loop: "{{ vultr_instance_ssh_keys }}"
+
+- name: setup create server
+ vultr.cloud.instance:
+ label: "{{ vultr_instance_name }}"
+ os: Debian 11 x64 (bullseye)
+ plan: "{{ vultr_instance_plan }}"
+ ssh_keys:
+ - "{{ vultr_resource_prefix }}_key1"
+ region: "{{ vultr_block_storage_region }}"
+ register: result_server_setup
+
+- name: wait some time
+ wait_for:
+ timeout: 20
+
+- name: setup block storage volume unattached
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ attached_to_instance: ""
+ register: result
+- name: verify test create block storage volume
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - not result.vultr_block_storage.attached_to_instance
+ - result.vultr_block_storage.label == vultr_block_storage_name
+ - result.vultr_block_storage.region == vultr_block_storage_region
+ - result.vultr_block_storage.size_gb == 10
+
+- name: test attach block volume in check mode
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ attached_to_instance: "{{ result_server_setup.vultr_instance.id }}"
+ register: result
+ check_mode: true
+- name: verify test attach block volume in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - not result.vultr_block_storage.attached_to_instance
+
+- name: test attach block volume
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ attached_to_instance: "{{ result_server_setup.vultr_instance.id }}"
+ register: result
+ until: "'fetch_url_info' not in result or result.fetch_url_info.find('unable to attach') != -1"
+ retries: 3
+ delay: 10
+- name: verify test attach block volume
+ ansible.builtin.assert:
+ that:
+ - result.changed
+ - result.vultr_block_storage.attached_to_instance == result_server_setup.vultr_instance.id
+
+- name: test attach block volume idempotency
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ attached_to_instance: "{{ result_server_setup.vultr_instance.id }}"
+ register: result
+- name: verify test attach block volume idempotency
+ ansible.builtin.assert:
+ that:
+ - not result.changed
+ - result.vultr_block_storage.attached_to_instance == result_server_setup.vultr_instance.id
+
+# volume size can only be modified every 60s
+- name: wait about 60s before resizing volume
+ wait_for:
+ timeout: 61
+
+- name: test resize block storage volume while attached
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size_2 }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ attached_to_instance: "{{ result_server_setup.vultr_instance.id }}"
+ register: result
+- name: verify test resize block storage volume while attached
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_block_storage.attached_to_instance == result_server_setup.vultr_instance.id
+
+- name: wait about 60s
+ wait_for:
+ timeout: 61
+
+- name: test detach block volume in check mode
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size_2 }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ attached_to_instance: ""
+ register: result
+ check_mode: true
+- name: verify test detach block volume in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_block_storage.attached_to_instance == result_server_setup.vultr_instance.id
+
+- name: test detach block volume
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size_2 }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ attached_to_instance: ""
+ register: result
+- name: verify test detach block volume
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - not result.vultr_block_storage.attached_to_instance
+
+- name: test detach block volume idempotency
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size_2 }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+ region: "{{ vultr_block_storage_region }}"
+ attached_to_instance: ""
+ register: result
+- name: verify test detach block volume idempotency
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - not result.vultr_block_storage.attached_to_instance
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/defaults/main.yml
new file mode 100644
index 000000000..8e433a2aa
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/defaults/main.yml
@@ -0,0 +1,7 @@
+---
+vultr_resource_prefix: "vultr-test-prefix"
+vultr_block_storage_name: "{{ vultr_resource_prefix }}-volume"
+vultr_block_storage_size: 10
+vultr_block_storage_region: ewr
+
+vultr_block_storage_block_type: high_perf
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/tasks/main.yml
new file mode 100644
index 000000000..bb27c3b95
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_block_storage
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/tasks/tests.yml
new file mode 100644
index 000000000..2f836ea09
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/block_storage_info/tasks/tests.yml
@@ -0,0 +1,36 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test gather vultr block storage volume info - empty resource
+ vultr.cloud.block_storage_info:
+
+- name: Create the block storage volume
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ size_gb: "{{ vultr_block_storage_size }}"
+ region: "{{ vultr_block_storage_region }}"
+ block_type: "{{ vultr_block_storage_block_type }}"
+
+- name: test gather vultr block storage volume info in check mode
+ vultr.cloud.block_storage_info:
+ check_mode: true
+ register: result
+
+- name: verify test gather vultr block storage volume info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_block_storage_info|selectattr('label','equalto','{{ vultr_block_storage_name }}') | list | count == 1
+
+- name: test gather vultr block storage volume info
+ vultr.cloud.block_storage_info:
+ register: result
+
+- name: verify test gather vultr block storage volume info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_block_storage_info|selectattr('label','equalto','{{ vultr_block_storage_name }}') | list | count == 1
+
+- name: Delete the block storage volume
+ vultr.cloud.block_storage:
+ label: "{{ vultr_block_storage_name }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/aliases
new file mode 100644
index 000000000..136c05e0d
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/aliases
@@ -0,0 +1 @@
+hidden
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/defaults/main.yml
new file mode 100644
index 000000000..02ff5e549
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+vultr_api_url: https://api.vultr.com/v2
+vultr_api_key: "{{ lookup('env', 'VULTR_API_KEY') }}"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_block_storage.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_block_storage.yml
new file mode 100644
index 000000000..cc25e8076
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_block_storage.yml
@@ -0,0 +1,29 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List blocks
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/blocks"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all blocks created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/blocks/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.label
+ with_items: "{{ res.json.blocks }}"
+ loop_control:
+ label: "{{ item.label }}"
+ no_log: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_dns_domain.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_dns_domain.yml
new file mode 100644
index 000000000..47eeefac5
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_dns_domain.yml
@@ -0,0 +1,29 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List dns domains
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/domains"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all dns domains created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/domains/{{ item.domain }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.domain
+ with_items: "{{ res.json.domains }}"
+ loop_control:
+ label: "{{ item.domain }}"
+ no_log: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_firewall_group.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_firewall_group.yml
new file mode 100644
index 000000000..74f9f4af4
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_firewall_group.yml
@@ -0,0 +1,28 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List firewall groups
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/firewalls"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all firewall groups created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/firewalls/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.description
+ with_items: "{{ res.json.firewall_groups }}"
+ loop_control:
+ label: "{{ item.description }}"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_instance.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_instance.yml
new file mode 100644
index 000000000..cad956b39
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_instance.yml
@@ -0,0 +1,29 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List instances
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/instances"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all instances created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/instances/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.label
+ with_items: "{{ res.json.instances }}"
+ loop_control:
+ label: "{{ item.label }}"
+ no_log: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_network.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_network.yml
new file mode 100644
index 000000000..3d82d93e5
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_network.yml
@@ -0,0 +1,29 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List networks
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/private-networks"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all networks created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/private-networks/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.description
+ with_items: "{{ res.json.networks }}"
+ loop_control:
+ label: "{{ item.description }}"
+ no_log: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_reserved_ip.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_reserved_ip.yml
new file mode 100644
index 000000000..7be9c46f4
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_reserved_ip.yml
@@ -0,0 +1,29 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List reserved-ips
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/reserved-ips"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all reserved-ips created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/reserved-ips/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.label
+ with_items: "{{ res.json.reserved_ips }}"
+ loop_control:
+ label: "{{ item.label }}"
+ no_log: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_snapshot.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_snapshot.yml
new file mode 100644
index 000000000..90200bbcd
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_snapshot.yml
@@ -0,0 +1,29 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List snapshots
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/snapshots"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all snapshots created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/snapshots/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.description
+ with_items: "{{ res.json.snapshots }}"
+ loop_control:
+ label: "{{ item.description }}"
+ no_log: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_ssh_key.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_ssh_key.yml
new file mode 100644
index 000000000..c217d4f39
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_ssh_key.yml
@@ -0,0 +1,29 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List ssh-keys
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/ssh-keys"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all ssh-keys created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/ssh-keys/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.name
+ with_items: "{{ res.json.ssh_keys }}"
+ loop_control:
+ label: "{{ item.name }}"
+ no_log: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_startup_script.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_startup_script.yml
new file mode 100644
index 000000000..3201dbdcb
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_startup_script.yml
@@ -0,0 +1,29 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List startup-scripts
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/startup-scripts"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all startup-scripts created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/startup-scripts/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.name
+ with_items: "{{ res.json.startup_scripts }}"
+ loop_control:
+ label: "{{ item.name }}"
+ no_log: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_user.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_user.yml
new file mode 100644
index 000000000..cd3173efa
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_user.yml
@@ -0,0 +1,29 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List users
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/users"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all users created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/users/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.name
+ with_items: "{{ res.json.users }}"
+ loop_control:
+ label: "{{ item.name }}"
+ no_log: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_vpc.yml b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_vpc.yml
new file mode 100644
index 000000000..f0c8e2b5c
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/cleanup/tasks/cleanup_vpc.yml
@@ -0,0 +1,33 @@
+---
+- name: cleanup
+ when: vultr_api_key
+ block:
+ - name: List vpcs
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/vpcs"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 200
+ register: res
+ no_log: true
+
+ - name: Found resources
+ ansible.builtin.debug:
+ var: res.json
+
+ - name: Remove all vpcs created by this test run
+ ansible.builtin.uri:
+ url: "{{ vultr_api_url }}/vpcs/{{ item.id }}"
+ method: "DELETE"
+ headers:
+ Authorization: Bearer {{ vultr_api_key }}
+ status_code: 204
+ when: vultr_resource_prefix in item.description
+ with_items: "{{ res.json.vpcs }}"
+ loop_control:
+ label: "{{ item.description }}"
+ pause: 2
+ retries: 5
+ delay: 3
+ register: result
+ until: result is not failed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/common/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/common/aliases
new file mode 100644
index 000000000..136c05e0d
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/common/aliases
@@ -0,0 +1 @@
+hidden
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/common/default/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/common/default/main.yml
new file mode 100644
index 000000000..1885f66e2
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/common/default/main.yml
@@ -0,0 +1,4 @@
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_resource_prefix: "{{ lookup('env', 'VULTR_RESOURCE_PREFIX') }}"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/defaults/main.yml
new file mode 100644
index 000000000..1f2f9a16a
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/defaults/main.yml
@@ -0,0 +1,4 @@
+# Copyright (c) 2018, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_dns_domain_name: "{{ vultr_resource_prefix }}-t1-vultr.com"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/tasks/main.yml
new file mode 100644
index 000000000..b26b845b3
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - name: cleanup dns domain
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ state: absent
+ ignore_errors: true
+
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_dns_domain
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/tasks/tests.yml
new file mode 100644
index 000000000..d688ad12d
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain/tasks/tests.yml
@@ -0,0 +1,138 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ state: absent
+
+- name: test fail if missing name
+ vultr.cloud.dns_domain:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing name
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: domain"'
+
+- name: test fail if missing params for state=present
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ register: result
+ ignore_errors: true
+- name: verify fail if missing params for state=present
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "state is present but all of the following are missing: ip"'
+
+- name: test create dns domain in check mode
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ dns_sec: enabled
+ server_ip: 10.10.10.10
+ register: result
+ check_mode: true
+- name: verify test create dns domain in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create dns domain
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ dns_sec: enabled
+ server_ip: 10.10.10.10
+ register: result
+- name: verify test create dns domain
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_domain.domain == vultr_dns_domain_name
+ - result.vultr_dns_domain.dns_sec == 'enabled'
+
+- name: test create dns domain idempotence
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ dns_sec: enabled
+ server_ip: 10.10.10.10
+ register: result
+- name: verify test create dns domain idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_dns_domain.domain == vultr_dns_domain_name
+ - result.vultr_dns_domain.dns_sec == 'enabled'
+
+- name: test update dns domain in check mode
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ dns_sec: disabled
+ server_ip: 10.10.10.10
+ register: result
+ check_mode: true
+- name: verify test create dns domain in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_domain.dns_sec == 'enabled'
+
+- name: test update dns domain
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ dns_sec: disabled
+ server_ip: 10.10.10.10
+ register: result
+- name: verify test create dns domain
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_domain.domain == vultr_dns_domain_name
+ - result.vultr_dns_domain.dns_sec == 'disabled'
+
+- name: test update dns domain idempotence
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ dns_sec: disabled
+ server_ip: 10.10.10.10
+ register: result
+- name: verify test create dns domain idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_dns_domain.domain == vultr_dns_domain_name
+ - result.vultr_dns_domain.dns_sec == 'disabled'
+
+- name: test absent dns domain in check mode
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test absent dns domain in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_domain.domain == vultr_dns_domain_name
+
+- name: test absent dns domain
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ state: absent
+ register: result
+- name: verify test absent dns domain
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_domain.domain == vultr_dns_domain_name
+
+- name: test absent dns domain idempotence
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ state: absent
+ register: result
+- name: verify test absent dns domain idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/defaults/main.yml
new file mode 100644
index 000000000..23d527820
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+dns_domain_name: "{{ vultr_resource_prefix }}-t2-vultr.com"
+dns_domain_server_ip: 104.24.16.59
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/tasks/main.yml
new file mode 100644
index 000000000..3f65737a7
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - name: cleanup the domain
+ vultr.cloud.dns_domain:
+ name: "{{ dns_domain_name }}"
+ state: absent
+ ignore_errors: true
+
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_dns_domain
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/tasks/tests.yml
new file mode 100644
index 000000000..f772ab637
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_domain_info/tasks/tests.yml
@@ -0,0 +1,27 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Create a domain
+ vultr.cloud.dns_domain:
+ name: "{{ dns_domain_name }}"
+ server_ip: "{{ dns_domain_server_ip }}"
+
+- name: test gather vultr dns domain info in check mode
+ vultr.cloud.dns_domain_info:
+ check_mode: true
+ register: result
+
+- name: verify test gather vultr dns domain info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_dns_domain_info|selectattr('domain','equalto','{{ dns_domain_name }}') | list | count == 1
+
+- name: test gather vultr dns domain info
+ vultr.cloud.dns_domain_info:
+ register: result
+
+- name: verify test gather vultr dns domain info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_dns_domain_info|selectattr('domain','equalto','{{ dns_domain_name }}') | list | count == 1
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/defaults/main.yml
new file mode 100644
index 000000000..e979dc89b
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/defaults/main.yml
@@ -0,0 +1,38 @@
+# Copyright (c) 2021 René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_dns_domain_name: "{{ vultr_resource_prefix }}-t3-vultr.com"
+
+vultr_dns_record_items:
+ # Single A record
+ - name: test-www
+ data: 10.10.10.10
+ ttl: 400
+ update_data: 10.10.10.11
+ update_ttl: 200
+
+ # Multiple A records
+ - name: test-www-multiple
+ data: 10.10.11.10
+ update_data: 10.10.11.11
+ multiple: true
+
+ # CNAME
+ - name: test-cname
+ data: www.ansible.com
+ update_data: www.ansible.ch
+ record_type: CNAME
+
+ # Single Multiple MX record
+ - data: mx1.example-ansible.com
+ priority: 10
+ update_priority: 20
+ record_type: MX
+
+ # Multiple MX records
+ - data: mx2.example-ansible.com
+ priority: 10
+ update_data: mx1.example-ansible.com
+ update_priority: 20
+ record_type: MX
+ multiple: true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/create_record.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/create_record.yml
new file mode 100644
index 000000000..39964c138
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/create_record.yml
@@ -0,0 +1,62 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup dns record absent
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ state: absent
+
+- name: test create a dns record in check mode
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.data }}"
+ ttl: "{{ item.ttl | default(omit) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ priority: "{{ item.priority | default(omit) }}"
+ check_mode: True
+ register: result
+- name: verify test create a dns record in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create a dns record
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.data }}"
+ ttl: "{{ item.ttl | default(omit) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ priority: "{{ item.priority | default(omit) }}"
+ register: result
+- name: verify test create a dns record
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_record.data == "{{ item.data }}"
+ - result.vultr_dns_record.name == "{{ item.name | default("") }}"
+ - result.vultr_dns_record.type == "{{ item.record_type | default('A') }}"
+ - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }}
+ - result.vultr_dns_record.priority == {{ item.priority | default(-1) }}
+
+- name: test create a dns record idempotence
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.data }}"
+ ttl: "{{ item.ttl | default(omit) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ priority: "{{ item.priority | default(omit) }}"
+ register: result
+- name: verify test create a dns record idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_dns_record.data == "{{ item.data }}"
+ - result.vultr_dns_record.name == "{{ item.name | default("") }}"
+ - result.vultr_dns_record.type == "{{ item.record_type | default('A') }}"
+ - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }}
+ - result.vultr_dns_record.priority == {{ item.priority | default(-1) }}
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/main.yml
new file mode 100644
index 000000000..b26b845b3
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - name: cleanup dns domain
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ state: absent
+ ignore_errors: true
+
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_dns_domain
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/record.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/record.yml
new file mode 100644
index 000000000..6426d4bcf
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/record.yml
@@ -0,0 +1,6 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- ansible.builtin.import_tasks: create_record.yml
+- ansible.builtin.import_tasks: update_record.yml
+- ansible.builtin.import_tasks: remove_record.yml
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/remove_record.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/remove_record.yml
new file mode 100644
index 000000000..1207ea250
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/remove_record.yml
@@ -0,0 +1,114 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test remove a dns record in check mode
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.update_data | default(item.data) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ multiple: "{{ item.multiple | default(omit) }}"
+ state: absent
+ check_mode: true
+ register: result
+- name: verify test remove a dns record in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_record.data == "{{ item.update_data | default(item.data) }}"
+ - result.vultr_dns_record.name == "{{ item.name | default("") }}"
+ - result.vultr_dns_record.type == "{{ item.record_type | default('A') }}"
+ - result.vultr_dns_record.ttl == {{ item.update_ttl | default(300) }}
+ - result.vultr_dns_record.priority == {{ item.update_priority | default(item.priority | default(-1)) }}
+
+- name: test remove second dns record in check mode
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.data | default(item.data) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ multiple: "{{ item.multiple | default(omit) }}"
+ state: absent
+ check_mode: true
+ register: result
+ when: item.multiple is defined and item.multiple == true
+- name: verify test remove a dns record in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_record.data == "{{ item.data | default(item.data) }}"
+ - result.vultr_dns_record.name == "{{ item.name | default("") }}"
+ - result.vultr_dns_record.type == "{{ item.record_type | default('A') }}"
+ - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }}
+ - result.vultr_dns_record.priority == {{ item.priority | default(-1) }}
+ when: item.multiple is defined and item.multiple == true
+
+- name: test remove a dns record
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.update_data | default(item.data) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ multiple: "{{ item.multiple | default(omit) }}"
+ state: absent
+ register: result
+- name: verify test remove a dns record
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_record.data == "{{ item.update_data | default(item.data) }}"
+ - result.vultr_dns_record.name == "{{ item.name | default("") }}"
+ - result.vultr_dns_record.type == "{{ item.record_type | default('A') }}"
+ - result.vultr_dns_record.ttl == {{ item.update_ttl | default(300) }}
+ - result.vultr_dns_record.priority == {{ item.update_priority | default(item.priority | default(-1)) }}
+
+- name: test remove second dns record
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.data }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ multiple: "{{ item.multiple | default(omit) }}"
+ state: absent
+ register: result
+ when: item.multiple is defined and item.multiple == true
+- name: verify test remove a dns record
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_record.data == "{{ item.data }}"
+ - result.vultr_dns_record.name == "{{ item.name | default("") }}"
+ - result.vultr_dns_record.type == "{{ item.record_type | default('A') }}"
+ - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }}
+ - result.vultr_dns_record.priority == {{ item.priority | default(-1) }}
+ when: item.multiple is defined and item.multiple == true
+
+- name: test remove a dns record idempotence
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.update_data | default(item.data) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ multiple: "{{ item.multiple | default(omit) }}"
+ state: absent
+ register: result
+- name: verify test remove a dns record idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+
+- name: test remove second dns record idempotence
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.data }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ multiple: "{{ item.multiple | default(omit) }}"
+ state: absent
+ register: result
+ when: item.multiple is defined and item.multiple == true
+- name: verify test remove a dns record idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ when: item.multiple is defined and item.multiple == true
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/test_fail_multiple.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/test_fail_multiple.yml
new file mode 100644
index 000000000..9d18c5b47
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/test_fail_multiple.yml
@@ -0,0 +1,78 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup first dns record
+ vultr.cloud.dns_record:
+ name: test-multiple
+ domain: "{{ vultr_dns_domain_name }}"
+ data: 1.2.3.4
+ multiple: true
+ register: result
+- name: verify setup a dns record
+ ansible.builtin.assert:
+ that:
+ - result is successful
+
+- name: setup second dns record
+ vultr.cloud.dns_record:
+ name: test-multiple
+ domain: "{{ vultr_dns_domain_name }}"
+ data: 1.2.3.5
+ multiple: true
+ register: result
+- name: verify setup second dns record
+ ansible.builtin.assert:
+ that:
+ - result is successful
+
+- name: test-multiple fail multiple identical records found
+ vultr.cloud.dns_record:
+ name: test-multiple
+ domain: "{{ vultr_dns_domain_name }}"
+ state: absent
+ register: result
+ ignore_errors: true
+- name: verify test fail multiple identical records found
+ ansible.builtin.assert:
+ that:
+ - result is failed
+
+- name: test-multiple fail absent multiple identical records but not data
+ vultr.cloud.dns_record:
+ name: test-multiple
+ domain: "{{ vultr_dns_domain_name }}"
+ state: absent
+ multiple: true
+ register: result
+ ignore_errors: true
+- name: verify test-multiple success absent multiple identical records found
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - "result.msg == 'multiple is True but all of the following are missing: data'"
+
+- name: test-multiple success absent multiple identical records second found
+ vultr.cloud.dns_record:
+ name: test-multiple
+ domain: "{{ vultr_dns_domain_name }}"
+ data: 1.2.3.5
+ state: absent
+ multiple: true
+ register: result
+- name: verify test-multiple success absent multiple identical records second found
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test-multiple success absent multiple identical records first found
+ vultr.cloud.dns_record:
+ name: test-multiple
+ domain: "{{ vultr_dns_domain_name }}"
+ data: 1.2.3.4
+ state: absent
+ multiple: true
+ register: result
+- name: verify test-multiple success absent multiple identical records firstfound
+ ansible.builtin.assert:
+ that:
+ - result is changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/tests.yml
new file mode 100644
index 000000000..0251942d7
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/tests.yml
@@ -0,0 +1,12 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup dns domain
+ vultr.cloud.dns_domain:
+ name: "{{ vultr_dns_domain_name }}"
+ server_ip: 10.10.10.10
+
+- ansible.builtin.import_tasks: test_fail_multiple.yml
+
+- ansible.builtin.include_tasks: record.yml
+ with_items: "{{ vultr_dns_record_items }}"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/update_record.yml b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/update_record.yml
new file mode 100644
index 000000000..f79beccf5
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/dns_record/tasks/update_record.yml
@@ -0,0 +1,70 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test update or add another dns record in check mode
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.update_data | default(item.data) }}"
+ ttl: "{{ item.update_ttl | default(omit) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ priority: "{{ item.update_priority | default(omit) }}"
+ multiple: "{{ item.multiple | default(omit) }}"
+ check_mode: true
+ register: result
+- name: verify test update or add another dns record in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_record.data == "{{ item.data }}"
+ - result.vultr_dns_record.name == "{{ item.name | default("") }}"
+ - result.vultr_dns_record.type == "{{ item.record_type | default('A') }}"
+ - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }}
+ - result.vultr_dns_record.priority == {{ item.priority | default(-1) }}
+ when: item.multiple is undefined or item.multiple == false
+- name: verify test add another dns record in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - not result.vultr_dns_record
+ when: item.multiple is defined and item.multiple == true
+
+- name: test update or add another dns record
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.update_data | default(item.data) }}"
+ ttl: "{{ item.update_ttl | default(omit) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ priority: "{{ item.update_priority | default(omit) }}"
+ multiple: "{{ item.multiple | default(omit) }}"
+ register: result
+- name: verify test update a dns record
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_dns_record.data == "{{ item.update_data | default(item.data) }}"
+ - result.vultr_dns_record.name == "{{ item.name | default("") }}"
+ - result.vultr_dns_record.ttl == {{ item.update_ttl | default(300) }}
+ - result.vultr_dns_record.type == "{{ item.record_type | default('A') }}"
+ - result.vultr_dns_record.priority == {{ item.update_priority | default(-1) }}
+
+- name: test update or add another dns record idempotence
+ vultr.cloud.dns_record:
+ name: "{{ item.name | default(omit) }}"
+ domain: "{{ vultr_dns_domain_name }}"
+ data: "{{ item.update_data | default(item.data) }}"
+ ttl: "{{ item.update_ttl | default(omit) }}"
+ record_type: "{{ item.record_type | default(omit) }}"
+ priority: "{{ item.update_priority | default(omit) }}"
+ multiple: "{{ item.multiple | default(omit) }}"
+ register: result
+- name: verify test update a dns record idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_dns_record.data == "{{ item.update_data | default(item.data) }}"
+ - result.vultr_dns_record.name == "{{ item.name | default("") }}"
+ - result.vultr_dns_record.ttl == {{ item.update_ttl | default(300) }}
+ - result.vultr_dns_record.type == "{{ item.record_type | default('A') }}"
+ - result.vultr_dns_record.priority == {{ item.update_priority | default(-1) }}
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/defaults/main.yml
new file mode 100644
index 000000000..a5e9c5576
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/defaults/main.yml
@@ -0,0 +1,4 @@
+# Copyright (c) 2018, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_firewall_group_name: "{{ vultr_resource_prefix }}_firewall-group"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/tasks/main.yml
new file mode 100644
index 000000000..29ddee8e1
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_firewall_group
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/tasks/tests.yml
new file mode 100644
index 000000000..578fc6efb
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group/tasks/tests.yml
@@ -0,0 +1,86 @@
+# Copyright (c) 2018, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_firewall_group_name }}"
+ state: absent
+ register: result
+- name: verify setup
+ ansible.builtin.assert:
+ that:
+ - result is success
+
+- name: test fail if missing name
+ vultr.cloud.firewall_group:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing description
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: description"'
+
+- name: test create firewall group in check mode
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_firewall_group_name }}"
+ register: result
+ check_mode: true
+- name: verify test create firewall group in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create firewall group
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_firewall_group_name }}"
+ register: result
+- name: verify test create firewall group
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_firewall_group.description == vultr_firewall_group_name
+
+- name: test create firewall group idempotence
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_firewall_group_name }}"
+
+ register: result
+- name: verify test create firewall group idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_firewall_group.description == vultr_firewall_group_name
+
+- name: test absent firewall group in check mode
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_firewall_group_name }}"
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test absent firewall group in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_firewall_group.description == vultr_firewall_group_name
+
+- name: test absent firewall group
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_firewall_group_name }}"
+ state: absent
+ register: result
+- name: verify test absent firewall group
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_firewall_group.description == vultr_firewall_group_name
+
+- name: test absent firewall group idempotence
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_firewall_group_name }}"
+ state: absent
+ register: result
+- name: verify test absent firewall group idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/defaults/main.yml
new file mode 100644
index 000000000..a420cc51b
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+firewall_group_name: "{{ vultr_resource_prefix }}_firewall-group"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/tasks/main.yml
new file mode 100644
index 000000000..29ddee8e1
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_firewall_group
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/tasks/tests.yml
new file mode 100644
index 000000000..390150418
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_group_info/tasks/tests.yml
@@ -0,0 +1,34 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test gather vultr firewall group info - empty resources
+ vultr.cloud.firewall_group_info:
+
+- name: Create the firewall group
+ vultr.cloud.firewall_group:
+ name: "{{ firewall_group_name }}"
+
+- name: test gather vultr firewall group info in check mode
+ vultr.cloud.firewall_group_info:
+ check_mode: true
+ register: result
+
+- name: verify test gather vultr firewall group info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_firewall_group_info|selectattr('description','equalto','{{ firewall_group_name }}') | list | count == 1
+
+- name: test gather vultr firewall group info
+ vultr.cloud.firewall_group_info:
+ register: result
+
+- name: verify test gather vultr firewall group info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_firewall_group_info|selectattr('description','equalto','{{ firewall_group_name }}') | list | count == 1
+
+- name: Delete the firewall group
+ vultr.cloud.firewall_group:
+ name: "{{ firewall_group_name }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/defaults/main.yml
new file mode 100644
index 000000000..7e96b1f83
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/defaults/main.yml
@@ -0,0 +1,40 @@
+# Copyright (c) 2018, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_firewall_group_name: "{{ vultr_resource_prefix }}_firewall-group"
+vultr_firewall_rules:
+ - notes: DNS TCP v4
+ port: "53"
+ subnet: "0.0.0.0"
+ subnet_size: 0
+
+ - notes: DNS UDP v4
+ port: "53"
+ protocol: udp
+ subnet: "0.0.0.0"
+ subnet_size: 0
+
+ - notes: DNS tcp v6
+ port: "53"
+ port_update: "5353"
+ protocol: tcp
+ ip_type: v6
+ subnet: "::"
+ subnet_size: 0
+
+ - notes: DNS UDP v6
+ port: "53"
+ protocol: udp
+ ip_type: v6
+ subnet: "::"
+ subnet_size: 0
+
+ - notes: allow ICMP
+ protocol: icmp
+ subnet: "0.0.0.0"
+ subnet_size: 0
+
+ - notes: web app
+ port: "8000:8080"
+ subnet: "192.168.23.0"
+ subnet_size: 24
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/main.yml
new file mode 100644
index 000000000..66fd850fa
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/main.yml
@@ -0,0 +1,8 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - name: cleanup firewall group and rules
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_firewall_group_name }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/rule_absent.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/rule_absent.yml
new file mode 100644
index 000000000..a8fe6f60a
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/rule_absent.yml
@@ -0,0 +1,62 @@
+---
+- name: rule info
+ ansible.builtin.debug:
+ var: rule
+
+- name: test absent firewall rule in check mode
+ vultr.cloud.firewall_rule:
+ group: "{{ vultr_firewall_group_name }}"
+ ip_type: "{{ rule.ip_type | default('v4') }}"
+ port: "{{ rule.port | default(omit) }}"
+ protocol: "{{ rule.protocol | default(omit) }}"
+ subnet: "{{ rule.subnet | default(omit) }}"
+ subnet_size: "{{ rule.subnet_size | default(omit) }}"
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test absent firewall rule in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_firewall_rule.action == "accept"
+ - result.vultr_firewall_rule.protocol == "{{ rule.protocol | default('tcp') }}"
+ - result.vultr_firewall_rule.port == "{{ rule.port | default('') }}"
+ - result.vultr_firewall_rule.subnet == "{{ rule.subnet | default('') }}"
+ - result.vultr_firewall_rule.subnet_size == {{ rule.subnet_size | default(0) }}
+ - result.vultr_firewall_rule.ip_type == "{{ rule.ip_type | default('v4') }}"
+
+- name: test absent firewall rule
+ vultr.cloud.firewall_rule:
+ group: "{{ vultr_firewall_group_name }}"
+ ip_type: "{{ rule.ip_type | default('v4') }}"
+ port: "{{ rule.port | default(omit) }}"
+ protocol: "{{ rule.protocol | default(omit) }}"
+ subnet: "{{ rule.subnet | default(omit) }}"
+ subnet_size: "{{ rule.subnet_size | default(omit) }}"
+ state: absent
+ register: result
+- name: verify test absent firewall rule
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_firewall_rule.action == "accept"
+ - result.vultr_firewall_rule.protocol == "{{ rule.protocol | default('tcp') }}"
+ - result.vultr_firewall_rule.port == "{{ rule.port | default('') }}"
+ - result.vultr_firewall_rule.subnet == "{{ rule.subnet | default('') }}"
+ - result.vultr_firewall_rule.subnet_size == {{ rule.subnet_size | default(0) }}
+ - result.vultr_firewall_rule.ip_type == "{{ rule.ip_type | default('v4') }}"
+
+- name: test absent firewall rule idempotence
+ vultr.cloud.firewall_rule:
+ group: "{{ vultr_firewall_group_name }}"
+ ip_type: "{{ rule.ip_type | default('v4') }}"
+ port: "{{ rule.port | default(omit) }}"
+ protocol: "{{ rule.protocol | default(omit) }}"
+ subnet: "{{ rule.subnet | default(omit) }}"
+ subnet_size: "{{ rule.subnet_size | default(omit) }}"
+ state: absent
+ register: result
+- name: verify test absent firewall rule idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/rule_present.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/rule_present.yml
new file mode 100644
index 000000000..9093b6aaf
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/rule_present.yml
@@ -0,0 +1,62 @@
+---
+- name: rule info
+ ansible.builtin.debug:
+ var: rule
+
+- name: test create firewall rule in check mode
+ vultr.cloud.firewall_rule:
+ group: "{{ vultr_firewall_group_name }}"
+ ip_type: "{{ rule.ip_type | default('v4') }}"
+ port: "{{ rule.port | default(omit) }}"
+ protocol: "{{ rule.protocol | default(omit) }}"
+ subnet: "{{ rule.subnet | default(omit) }}"
+ subnet_size: "{{ rule.subnet_size | default(omit) }}"
+ notes: "{{ rule.notes }}"
+ register: result
+ check_mode: true
+- name: verify test create firewall rule in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create firewall rule
+ vultr.cloud.firewall_rule:
+ group: "{{ vultr_firewall_group_name }}"
+ ip_type: "{{ rule.ip_type | default('v4') }}"
+ port: "{{ rule.port | default(omit) }}"
+ protocol: "{{ rule.protocol | default(omit) }}"
+ subnet: "{{ rule.subnet | default(omit) }}"
+ subnet_size: "{{ rule.subnet_size | default(omit) }}"
+ notes: "{{ rule.notes }}"
+ register: result
+- name: verify test create firewall rule
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_firewall_rule.action == "accept"
+ - result.vultr_firewall_rule.protocol == "{{ rule.protocol | default('tcp') }}"
+ - result.vultr_firewall_rule.port == "{{ rule.port | default('') }}"
+ - result.vultr_firewall_rule.subnet == "{{ rule.subnet | default('') }}"
+ - result.vultr_firewall_rule.subnet_size == {{ rule.subnet_size | default(0) }}
+ - result.vultr_firewall_rule.ip_type == "{{ rule.ip_type | default('v4') }}"
+
+- name: test create firewall rule idempotence
+ vultr.cloud.firewall_rule:
+ group: "{{ vultr_firewall_group_name }}"
+ ip_type: "{{ rule.ip_type | default('v4') }}"
+ port: "{{ rule.port | default(omit) }}"
+ protocol: "{{ rule.protocol | default(omit) }}"
+ subnet: "{{ rule.subnet | default(omit) }}"
+ subnet_size: "{{ rule.subnet_size | default(omit) }}"
+ notes: "{{ rule.notes }}"
+ register: result
+- name: verify test create firewall rule idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_firewall_rule.action == "accept"
+ - result.vultr_firewall_rule.protocol == "{{ rule.protocol | default('tcp') }}"
+ - result.vultr_firewall_rule.port == "{{ rule.port | default('') }}"
+ - result.vultr_firewall_rule.subnet == "{{ rule.subnet | default('') }}"
+ - result.vultr_firewall_rule.subnet_size == {{ rule.subnet_size | default(0) }}
+ - result.vultr_firewall_rule.ip_type == "{{ rule.ip_type | default('v4') }}"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/tests.yml
new file mode 100644
index 000000000..b823f689c
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule/tasks/tests.yml
@@ -0,0 +1,28 @@
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup firewall group
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_firewall_group_name }}"
+
+- name: test fail if missing group
+ vultr.cloud.firewall_rule:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing group
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: group"'
+
+- ansible.builtin.include_tasks: rule_present.yml
+ with_items: "{{ vultr_firewall_rules }}"
+ loop_control:
+ loop_var: rule
+ label: "{{ rule.notes }}"
+
+- ansible.builtin.include_tasks: rule_absent.yml
+ with_items: "{{ vultr_firewall_rules }}"
+ loop_control:
+ loop_var: rule
+ label: "{{ rule.notes }}"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/defaults/main.yml
new file mode 100644
index 000000000..a420cc51b
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+firewall_group_name: "{{ vultr_resource_prefix }}_firewall-group"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/tasks/main.yml
new file mode 100644
index 000000000..29ddee8e1
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_firewall_group
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/tasks/tests.yml
new file mode 100644
index 000000000..96bca9803
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/firewall_rule_info/tasks/tests.yml
@@ -0,0 +1,45 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup the firewall group
+ vultr.cloud.firewall_group:
+ name: "{{ firewall_group_name }}"
+
+- name: test gather vultr firewall rule info - empty resources
+ vultr.cloud.firewall_rule_info:
+ group: "{{ firewall_group_name }}"
+
+- name: setup create firewall rule
+ vultr.cloud.firewall_rule:
+ group: "{{ firewall_group_name }}"
+ ip_type: v4
+ port: "80"
+ protocol: tcp
+ subnet: "0.0.0.0"
+ subnet_size: 0
+ notes: "{{ firewall_group_name }}"
+
+- name: test gather vultr firewall rule info in check mode
+ vultr.cloud.firewall_rule_info:
+ group: "{{ firewall_group_name }}"
+ check_mode: true
+ register: result
+- name: verify test gather vultr firewall rule info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_firewall_rule_info|selectattr('notes','equalto','{{ firewall_group_name }}') | list | count == 1
+
+- name: test gather vultr firewall rule info
+ vultr.cloud.firewall_rule_info:
+ group: "{{ firewall_group_name }}"
+ register: result
+- name: verify test gather vultr firewall rule info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_firewall_rule_info|selectattr('notes','equalto','{{ firewall_group_name }}') | list | count == 1
+
+- name: Delete the firewall group
+ vultr.cloud.firewall_group:
+ name: "{{ firewall_group_name }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/instance/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance/defaults/main.yml
new file mode 100644
index 000000000..6683b5e85
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/defaults/main.yml
@@ -0,0 +1,95 @@
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_instance_firewall_group: "{{ vultr_resource_prefix }}_instance_fw_group"
+vultr_instance_ssh_key_name: "{{ vultr_resource_prefix }}_instance_sshkey"
+vultr_instance_ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAyWYItY+3w5b8PdGRoz0oY5mufqydW96naE+VM3JSvJFAUS08rAjQQpQ03ymoALeHQy6JVZbcgecxn6p0pAOINQdqufn4udPtOPCtMjNiPGpkSM9ah/6X5+kvyWMNrvlf+Ld4OOoszP5sAkgQzIbrFQAm41XknBUha0zkewZwfrVhain4pnDjV7wCcChId/Q/Gbi4xMtXkisznWcAJcueBs3EEZDKhJ5q0VeWSJEhYJDLFN1sOxF0AIUnMrOhfKQ/LjgREXPB6uCl899INUTXRNNjRpeMXyJ2wMMmOAbua2qEd1r13Bu1n+6A823Hzb33fyMXuqWnJwBJ4DCvMlGuEsfuOK+xk7DaBfLHbcM6fsPk0/4psTE6YLgC41remr6+u5ZWsY/faMtSnNPie8Z8Ov0DIYGdhbJjUXk1HomxRV9+ZfZ2Ob8iCwlaAQAyEUM6fs3Kxt8pBD8dx1HOkhsfBWPvuDr5y+kqE7H8/MuPDTc0QgH2pjUMpmw/XBwNDHshVEjrZvtICOjOLUJxcowLO1ivNYwPwowQxfisMy56LfYdjsOslBiqsrkAqvNGm1zu8wKHeqVN9w5l3yUELpvubfm9NKIvYcl6yWF36T0c5vE+g0DU/Jy4XpTj0hZG9QV2mRQcLJnd2pxQtJT7cPFtrn/+tgRxzjEtbDXummDV4sE= ansible@example.com"
+
+vutr_instance_vpcs:
+ - description: "{{ vultr_resource_prefix }}_instance_vpc_1"
+ v4_subnet: 192.168.42.0
+ v4_subnet_mask: 24
+ region: ams
+ - description: "{{ vultr_resource_prefix }}_instance_vpc_2"
+ v4_subnet: 192.168.23.0
+ v4_subnet_mask: 24
+ region: ams
+ - description: "{{ vultr_resource_prefix }}_instance_vpc_3"
+ v4_subnet: 192.168.98.0
+ v4_subnet_mask: 24
+ region: ams
+
+vultr_instances:
+ - label: "{{ vultr_resource_prefix }}_os1"
+ hostname: myhostname
+ user_data: |
+ #cloud-config
+ packages:
+ - htop
+ user_data_update: |
+ #cloud-config
+ packages:
+ - htop
+ - vim
+ plan: vc2-1c-1gb
+ plan_update: vc2-1c-2gb
+ ssh_keys:
+ - "{{ vultr_instance_ssh_key_name }}"
+ tags:
+ - one
+ - two
+ tags_update:
+ - three
+ - four
+ region: ams
+ os: Debian 11 x64 (bullseye)
+ backups: true
+ backups_update: false
+ ddos_protection: true
+ ddos_protection_update: false
+ enable_ipv6: false
+ enable_ipv6_update: true
+ vpcs:
+ - "{{ vultr_resource_prefix }}_instance_vpc_1"
+ - "{{ vultr_resource_prefix }}_instance_vpc_2"
+ vpcs_update:
+ - "{{ vultr_resource_prefix }}_instance_vpc_1"
+ - "{{ vultr_resource_prefix }}_instance_vpc_3"
+
+ #TODO: Disabled, this app does not exist anymore, find a new app
+ # - label: "{{ vultr_resource_prefix }}_app1"
+ # plan: vc2-1c-1gb
+ # plan_update: vc2-1c-2gb
+ # region: ams
+ # app: Docker on Ubuntu 20.04 x64
+ # backups: false
+ # backups_update: false
+ # ddos_protection: false
+ # ddos_protection_update: false
+ # enable_ipv6: false
+ # enable_ipv6_update: false
+ # vpcs:
+ # - "{{ vultr_resource_prefix }}_instance_vpc_1"
+ # - "{{ vultr_resource_prefix }}_instance_vpc_2"
+ # vpcs_update:
+ # - "{{ vultr_resource_prefix }}_instance_vpc_1"
+ # - "{{ vultr_resource_prefix }}_instance_vpc_3"
+
+ - label: "{{ vultr_resource_prefix }}_img1"
+ plan: vc2-1c-1gb
+ plan_update: vc2-1c-2gb
+ region: ams
+ image: NodeJS on Ubuntu 22.04
+ backups: false
+ backups_update: true
+ ddos_protection: false
+ ddos_protection_update: true
+ enable_ipv6: true
+ # API does not disable IPv6 once enabled.
+ enable_ipv6_update: true
+ vpcs:
+ - "{{ vultr_resource_prefix }}_instance_vpc_1"
+ - "{{ vultr_resource_prefix }}_instance_vpc_2"
+ vpcs_update:
+ - "{{ vultr_resource_prefix }}_instance_vpc_1"
+ - "{{ vultr_resource_prefix }}_instance_vpc_3"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/absent.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/absent.yml
new file mode 100644
index 000000000..828f7f97e
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/absent.yml
@@ -0,0 +1,38 @@
+---
+- name: instance info
+ ansible.builtin.debug:
+ var: instance
+
+- name: test absent instance in check mode
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test absent instance in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test absent instance
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: absent
+ register: result
+- name: verify test absent instance
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test absent instance idempotence
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: absent
+ register: result
+- name: verify test absent instance idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/failures.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/failures.yml
new file mode 100644
index 000000000..f22616901
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/failures.yml
@@ -0,0 +1,55 @@
+---
+- name: test fail if missing arguments
+ vultr.cloud.instance:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing arguments
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: label, region"'
+
+- name: test fail if missing arguments required one of
+ vultr.cloud.instance:
+ label: my label
+ plan: a plan
+ region: a region
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing arguments required one of
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - '"one of the following required" in result.msg'
+
+- name: test fail if ssh key not found
+ vultr.cloud.instance:
+ label: my label
+ plan: a plan
+ region: a region
+ os: Debian 11 x64 (bullseye)
+ ssh_keys:
+ - does-not-exist
+ register: result
+ ignore_errors: true
+- name: verify test fail if ssh key not found
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - '"SSH key names not found: does-not-exist" in result.msg'
+
+- name: test fail if vpc not found
+ vultr.cloud.instance:
+ label: my label
+ plan: a plan
+ region: a region
+ os: Debian 11 x64 (bullseye)
+ vpcs:
+ - does-not-exist
+ register: result
+ ignore_errors: true
+- name: verify test fail if vpc not found
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - '"VPCs not found: does-not-exist" in result.msg'
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/main.yml
new file mode 100644
index 000000000..3a1fba6e0
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/main.yml
@@ -0,0 +1,16 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_instance
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_firewall_group
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_ssh_key
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_vpc
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/present.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/present.yml
new file mode 100644
index 000000000..004a9c732
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/present.yml
@@ -0,0 +1,190 @@
+---
+- name: instance info
+ ansible.builtin.debug:
+ var: instance
+
+- name: test create instance in check mode
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ hostname: "{{ instance.hostname | default(omit) }}"
+ user_data: "{{ instance.user_data | default(omit) }}"
+ firewall_group: "{{ vultr_instance_firewall_group }}"
+ ssh_keys: "{{ instance.ssh_keys | default(omit) }}"
+ plan: "{{ instance.plan }}"
+ ddos_protection: "{{ instance.ddos_protection | default(omit) }}"
+ backups: "{{ instance.backups | default(omit) }}"
+ enable_ipv6: "{{ instance.enable_ipv6 | default(omit) }}"
+ tags: "{{ instance.tags | default(omit) }}"
+ region: "{{ instance.region }}"
+ os: "{{ instance.os | default(omit) }}"
+ app: "{{ instance.app | default(omit) }}"
+ image: "{{ instance.image | default(omit) }}"
+ snapshot: "{{ instance.snapshot | default(omit) }}"
+ vpcs: "{{ instance.vpcs | default(omit) }}"
+ register: result
+ check_mode: true
+- name: verify test create instance in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create instance
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ hostname: "{{ instance.hostname | default(omit) }}"
+ user_data: "{{ instance.user_data | default(omit) }}"
+ firewall_group: "{{ vultr_instance_firewall_group }}"
+ ssh_keys: "{{ instance.ssh_keys | default(omit) }}"
+ plan: "{{ instance.plan }}"
+ ddos_protection: "{{ instance.ddos_protection | default(omit) }}"
+ backups: "{{ instance.backups | default(omit) }}"
+ enable_ipv6: "{{ instance.enable_ipv6 | default(omit) }}"
+ tags: "{{ instance.tags | default(omit) }}"
+ region: "{{ instance.region }}"
+ os: "{{ instance.os | default(omit) }}"
+ app: "{{ instance.app | default(omit) }}"
+ image: "{{ instance.image | default(omit) }}"
+ snapshot: "{{ instance.snapshot | default(omit) }}"
+ vpcs: "{{ instance.vpcs | default(omit) }}"
+ register: result
+- name: verify test create instance
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_instance.plan == instance.plan
+ - result.vultr_instance.region == instance.region
+ - "result.vultr_instance.backups == '{{ 'enabled' if instance.backups else 'disabled' }}'"
+ - result.vultr_instance.ddos_protection == instance.ddos_protection
+ - result.vultr_instance.enable_ipv6 == instance.enable_ipv6
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_1') | list | count == 1
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_2') | list | count == 1
+ - result.vultr_instance.vpcs | list | count == 2
+
+- name: test create instance idempotence
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ hostname: "{{ instance.hostname | default(omit) }}"
+ user_data: "{{ instance.user_data | default(omit) }}"
+ firewall_group: "{{ vultr_instance_firewall_group }}"
+ ssh_keys: "{{ instance.ssh_keys | default(omit) }}"
+ plan: "{{ instance.plan }}"
+ ddos_protection: "{{ instance.ddos_protection | default(omit) }}"
+ backups: "{{ instance.backups | default(omit) }}"
+ enable_ipv6: "{{ instance.enable_ipv6 | default(omit) }}"
+ tags: "{{ instance.tags | default(omit) }}"
+ region: "{{ instance.region }}"
+ os: "{{ instance.os | default(omit) }}"
+ app: "{{ instance.app | default(omit) }}"
+ image: "{{ instance.image | default(omit) }}"
+ snapshot: "{{ instance.snapshot | default(omit) }}"
+ vpcs: "{{ instance.vpcs | default(omit) }}"
+ register: result
+- name: verify test create instance idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_instance.plan == instance.plan
+ - result.vultr_instance.region == instance.region
+ - "result.vultr_instance.backups == '{{ 'enabled' if instance.backups else 'disabled' }}'"
+ - result.vultr_instance.ddos_protection == instance.ddos_protection
+ - result.vultr_instance.enable_ipv6 == instance.enable_ipv6
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_1') | list | count == 1
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_2') | list | count == 1
+ - result.vultr_instance.vpcs | list | count == 2
+
+- name: test update instance in check mode
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ hostname: "{{ instance.hostname | default(omit) }}"
+ user_data: "{{ instance.user_data_update | default(omit) }}"
+ firewall_group: "{{ vultr_instance_firewall_group }}"
+ ssh_keys: "{{ instance.ssh_keys | default(omit) }}"
+ plan: "{{ instance.plan_update }}"
+ ddos_protection: "{{ instance.ddos_protection_update | default(omit) }}"
+ backups: "{{ instance.backups_update | default(omit) }}"
+ enable_ipv6: "{{ instance.enable_ipv6_update | default(omit) }}"
+ tags: "{{ instance.tags_update | default(omit) }}"
+ region: "{{ instance.region }}"
+ os: "{{ instance.os | default(omit) }}"
+ app: "{{ instance.app | default(omit) }}"
+ image: "{{ instance.image | default(omit) }}"
+ snapshot: "{{ instance.snapshot | default(omit) }}"
+ vpcs: "{{ instance.vpcs_update | default(omit) }}"
+ register: result
+ check_mode: true
+- name: verify test update instance in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_instance.plan == instance.plan
+ - result.vultr_instance.region == instance.region
+ - "result.vultr_instance.backups == '{{ 'enabled' if instance.backups else 'disabled' }}'"
+ - result.vultr_instance.ddos_protection == instance.ddos_protection
+ - result.vultr_instance.enable_ipv6 == instance.enable_ipv6
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_1') | list | count == 1
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_2') | list | count == 1
+ - result.vultr_instance.vpcs | list | count == 2
+
+- name: test update instance
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ hostname: "{{ instance.hostname | default(omit) }}"
+ user_data: "{{ instance.user_data_update | default(omit) }}"
+ firewall_group: "{{ vultr_instance_firewall_group }}"
+ ssh_keys: "{{ instance.ssh_keys | default(omit) }}"
+ plan: "{{ instance.plan_update }}"
+ ddos_protection: "{{ instance.ddos_protection_update | default(omit) }}"
+ backups: "{{ instance.backups_update | default(omit) }}"
+ enable_ipv6: "{{ instance.enable_ipv6_update | default(omit) }}"
+ tags: "{{ instance.tags_update | default(omit) }}"
+ region: "{{ instance.region }}"
+ os: "{{ instance.os | default(omit) }}"
+ app: "{{ instance.app | default(omit) }}"
+ image: "{{ instance.image | default(omit) }}"
+ snapshot: "{{ instance.snapshot | default(omit) }}"
+ vpcs: "{{ instance.vpcs_update | default(omit) }}"
+ register: result
+- name: verify test update instance
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_instance.plan == instance.plan_update
+ - result.vultr_instance.region == instance.region
+ - "result.vultr_instance.backups == '{{ 'enabled' if instance.backups_update else 'disabled' }}'"
+ - result.vultr_instance.ddos_protection == instance.ddos_protection_update
+ - result.vultr_instance.enable_ipv6 == instance.enable_ipv6_update
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_1') | list | count == 1
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_3') | list | count == 1
+ - result.vultr_instance.vpcs | list | count == 2
+
+- name: test update instance idempotence
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ hostname: "{{ instance.hostname | default(omit) }}"
+ user_data: "{{ instance.user_data_update | default(omit) }}"
+ firewall_group: "{{ vultr_instance_firewall_group }}"
+ ssh_keys: "{{ instance.ssh_keys | default(omit) }}"
+ plan: "{{ instance.plan_update }}"
+ ddos_protection: "{{ instance.ddos_protection_update | default(omit) }}"
+ backups: "{{ instance.backups_update | default(omit) }}"
+ enable_ipv6: "{{ instance.enable_ipv6_update | default(omit) }}"
+ tags: "{{ instance.tags_update | default(omit) }}"
+ region: "{{ instance.region }}"
+ os: "{{ instance.os | default(omit) }}"
+ app: "{{ instance.app | default(omit) }}"
+ image: "{{ instance.image | default(omit) }}"
+ snapshot: "{{ instance.snapshot | default(omit) }}"
+ vpcs: "{{ instance.vpcs_update | default(omit) }}"
+ register: result
+- name: verify test update instance idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_instance.plan == instance.plan_update
+ - result.vultr_instance.region == instance.region
+ - "result.vultr_instance.backups == '{{ 'enabled' if instance.backups_update else 'disabled' }}'"
+ - result.vultr_instance.ddos_protection == instance.ddos_protection_update
+ - result.vultr_instance.enable_ipv6 == instance.enable_ipv6_update
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_1') | list | count == 1
+ - result.vultr_instance.vpcs | selectattr('description','equalto','{{ vultr_resource_prefix }}_instance_vpc_3') | list | count == 1
+ - result.vultr_instance.vpcs | list | count == 2
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/reinstall.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/reinstall.yml
new file mode 100644
index 000000000..6365ac0f5
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/reinstall.yml
@@ -0,0 +1,28 @@
+---
+- name: instance info
+ ansible.builtin.debug:
+ var: instance
+
+- name: test reinstall instance in check mode
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: reinstalled
+ register: result
+ check_mode: true
+- name: verify test reinstall instance in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_instance.power_status == "running"
+
+- name: test reinstall instance
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: reinstalled
+ register: result
+- name: verify test reinstall instance
+ ansible.builtin.assert:
+ that:
+ - result is changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/stop-start.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/stop-start.yml
new file mode 100644
index 000000000..23cc3cd56
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/stop-start.yml
@@ -0,0 +1,78 @@
+---
+- name: instance info
+ ansible.builtin.debug:
+ var: instance
+
+- name: test stop instance in check mode
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: stopped
+ register: result
+ check_mode: true
+- name: verify test stop instance in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_instance.power_status == "running"
+
+- name: test stop instance
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: stopped
+ register: result
+- name: verify test stop instance
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_instance.power_status == "stopped"
+
+- name: test stop instance idempotence
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: stopped
+ register: result
+- name: verify test stop instance idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_instance.power_status == "stopped"
+
+- name: test start instance in check mode
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: started
+ register: result
+ check_mode: true
+- name: verify test start instance in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_instance.power_status == "stopped"
+
+- name: test start instance
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: started
+ register: result
+- name: verify test start instance
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_instance.power_status == "running"
+
+- name: test start instance idempotence
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: started
+ register: result
+- name: verify test start instance idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_instance.power_status == "running"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/tests.yml
new file mode 100644
index 000000000..e35c426de
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance/tasks/tests.yml
@@ -0,0 +1,70 @@
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: absent
+ with_items: "{{ vultr_instances }}"
+ loop_control:
+ loop_var: instance
+
+- ansible.builtin.import_tasks: failures.yml
+
+- name: setup firewall group
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_instance_firewall_group }}"
+
+- name: setup ssh key
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_instance_ssh_key_name }}"
+ ssh_key: "{{ vultr_instance_ssh_key }}"
+
+- name: setup vpcs
+ vultr.cloud.vpc:
+ description: "{{ item.description }}"
+ v4_subnet: "{{ item.v4_subnet }}"
+ v4_subnet_mask: "{{ item.v4_subnet_mask }}"
+ region: "{{ item.region }}"
+ with_items: "{{ vutr_instance_vpcs }}"
+
+- ansible.builtin.include_tasks: present.yml
+ with_items: "{{ vultr_instances }}"
+ loop_control:
+ loop_var: instance
+
+- ansible.builtin.include_tasks: stop-start.yml
+ with_items: "{{ vultr_instances }}"
+ loop_control:
+ loop_var: instance
+
+- ansible.builtin.include_tasks: reinstall.yml
+ vars:
+ instance: "{{ vultr_instances | first }}"
+
+- ansible.builtin.include_tasks: absent.yml
+ with_items: "{{ vultr_instances }}"
+ loop_control:
+ loop_var: instance
+
+- name: cleanup firewall group
+ vultr.cloud.firewall_group:
+ name: "{{ vultr_instance_firewall_group }}"
+ state: absent
+
+- name: cleanup ssh key
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_instance_ssh_key_name }}"
+ state: absent
+
+- name: cleanup vpcs
+ vultr.cloud.vpc:
+ description: "{{ item.description }}"
+ region: "{{ item.region }}"
+ state: absent
+ with_items: "{{ vutr_instance_vpcs }}"
+ retries: 5
+ delay: 3
+ register: result
+ until: result is not failed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/defaults/main.yml
new file mode 100644
index 000000000..463a901ed
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/defaults/main.yml
@@ -0,0 +1,23 @@
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_region1: ams
+vultr_region2: cdg
+
+vultr_instances:
+ - label: "{{ vultr_resource_prefix }}_info1"
+ hostname: info1
+ plan: vc2-1c-1gb
+ tags:
+ - one
+ - two
+ region: "{{ vultr_region1 }}"
+ os: Debian 11 x64 (bullseye)
+ - label: "{{ vultr_resource_prefix }}_info2"
+ hostname: info2
+ plan: vc2-1c-1gb
+ tags:
+ - three
+ - four
+ region: "{{ vultr_region2 }}"
+ os: Debian 11 x64 (bullseye)
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/tasks/main.yml
new file mode 100644
index 000000000..352cfa20a
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_instance
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/tasks/tests.yml
new file mode 100644
index 000000000..204d071af
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/instance_info/tasks/tests.yml
@@ -0,0 +1,62 @@
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ hostname: "{{ instance.hostname }}"
+ plan: "{{ instance.plan }}"
+ tags: "{{ instance.tags }}"
+ region: "{{ instance.region }}"
+ os: "{{ instance.os }}"
+ register: result
+ with_items: "{{ vultr_instances }}"
+ loop_control:
+ loop_var: instance
+
+- name: test gather vultr instance info in check mode
+ vultr.cloud.instance_info:
+ check_mode: true
+ register: result
+- name: verify test gather vultr instance info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_instance_info|selectattr('label','search','^{{ vultr_resource_prefix }}') | list | count == 2
+ - result.vultr_instance_info|selectattr('label','equalto','{{ vultr_resource_prefix }}_info1') | list | count == 1
+
+- name: test gather vultr instance info
+ vultr.cloud.instance_info:
+ register: result
+- name: verify test gather vultr instance info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_instance_info|selectattr('label','search','^{{ vultr_resource_prefix }}') | list | count == 2
+ - result.vultr_instance_info|selectattr('label','equalto','{{ vultr_resource_prefix }}_info1') | list | count == 1
+
+- name: test gather vultr instance info filter region
+ vultr.cloud.instance_info:
+ region: "{{ vultr_region1 }}"
+ register: result
+- name: verify test gather vultr instance info filter region
+ ansible.builtin.assert:
+ that:
+ - result.vultr_instance_info|selectattr('label','search','^{{ vultr_resource_prefix }}') | list | count == 1
+
+- name: test gather vultr instance info filter label
+ vultr.cloud.instance_info:
+ label: "{{ vultr_resource_prefix }}_info2"
+ register: result
+- name: verify test gather vultr instance info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_instance_info|selectattr('label','search','^{{ vultr_resource_prefix }}') | list | count == 1
+ - result.vultr_instance_info|selectattr('label','equalto','{{ vultr_resource_prefix }}_info2') | list | count == 1
+
+- name: cleanup
+ vultr.cloud.instance:
+ label: "{{ instance.label }}"
+ region: "{{ instance.region }}"
+ state: absent
+ with_items: "{{ vultr_instances }}"
+ loop_control:
+ loop_var: instance
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/os_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/os_info/aliases
new file mode 100644
index 000000000..bf469bb90
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/os_info/aliases
@@ -0,0 +1 @@
+cloud/vultr
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/os_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/os_info/tasks/main.yml
new file mode 100644
index 000000000..0bcdf2728
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/os_info/tasks/main.yml
@@ -0,0 +1,22 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test get vultr os infos in check mode
+ vultr.cloud.os_info:
+ check_mode: true
+ register: result
+
+- name: verify test get vultr os infos in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_os_info|selectattr('name','equalto', 'CentOS 7 x64') | list | count == 1
+
+- name: test get vultr os fact
+ vultr.cloud.os_info:
+ register: result
+
+- name: verify test get vultr os infos
+ ansible.builtin.assert:
+ that:
+ - result.vultr_os_info|selectattr('name','equalto', 'CentOS 7 x64') | list | count == 1
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/plan_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/plan_info/aliases
new file mode 100644
index 000000000..bf469bb90
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/plan_info/aliases
@@ -0,0 +1 @@
+cloud/vultr
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/plan_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/plan_info/tasks/main.yml
new file mode 100644
index 000000000..e0050803c
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/plan_info/tasks/main.yml
@@ -0,0 +1,22 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test gather vultr plan info in check mode
+ vultr.cloud.plan_info:
+ check_mode: true
+ register: result
+
+- name: verify test gather vultr plan info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_plan_info|selectattr('id','equalto','vhf-8c-32gb') | list | count == 1
+
+- name: test gather vultr plan info
+ vultr.cloud.plan_info:
+ register: result
+
+- name: verify test gather vultr plan info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_plan_info|selectattr('id','equalto','vhf-8c-32gb') | list | count == 1
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/plan_metal_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/plan_metal_info/aliases
new file mode 100644
index 000000000..bf469bb90
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/plan_metal_info/aliases
@@ -0,0 +1 @@
+cloud/vultr
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/plan_metal_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/plan_metal_info/tasks/main.yml
new file mode 100644
index 000000000..59824faa7
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/plan_metal_info/tasks/main.yml
@@ -0,0 +1,23 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2020, Simon Bärlocher <s.baerlocher@sbaerlocher.ch>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test gather vultr plan bare metal info in check mode
+ vultr.cloud.plan_metal_info:
+ check_mode: true
+ register: result
+
+- name: verify test gather vultr plan bare metal info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_plan_metal_info|selectattr('id','equalto','vbm-4c-32gb') | list | count == 1
+
+- name: test gather vultr plan baremetal info
+ vultr.cloud.plan_metal_info:
+ register: result
+
+- name: verify test gather vultr plan bare metal info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_plan_metal_info|selectattr('id','equalto','vbm-4c-32gb') | list | count == 1
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/region_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/region_info/aliases
new file mode 100644
index 000000000..bf469bb90
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/region_info/aliases
@@ -0,0 +1 @@
+cloud/vultr
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/region_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/region_info/tasks/main.yml
new file mode 100644
index 000000000..117ae24cc
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/region_info/tasks/main.yml
@@ -0,0 +1,22 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test gather vultr region info in check mode
+ vultr.cloud.region_info:
+ check_mode: true
+ register: result
+
+- name: verify test gather vultr region info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_region_info|selectattr('city','equalto','Atlanta') | list | count == 1
+
+- name: test gather vultr region info
+ vultr.cloud.region_info:
+ register: result
+
+- name: verify test gather vultr region info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_region_info|selectattr('city','equalto','Atlanta') | list | count == 1
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/aliases
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/aliases
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/defaults/main.yml
new file mode 100644
index 000000000..60634dbeb
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/defaults/main.yml
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_reserved_ip_name: "{{ vultr_resource_prefix }}-ip"
+
+# TODO: topic of changes
+vultr_server_name: "{{ vultr_resource_prefix }}_vm"
+vultr_server_os: CentOS 7 x64
+vultr_server_plan: 1024 MB RAM,25 GB SSD,1.00 TB BW
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/tasks/main.yml
new file mode 100644
index 000000000..22af95139
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/tasks/main.yml
@@ -0,0 +1,10 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_reserved_ip
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_instance
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/tasks/tests.yml
new file mode 100644
index 000000000..a46b56366
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/reserved_ip/tasks/tests.yml
@@ -0,0 +1,240 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ state: absent
+ register: result
+- name: verify setup
+ ansible.builtin.assert:
+ that:
+ - result is success
+
+- name: test fail if missing args
+ vultr.cloud.reserved_ip:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing args
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: ip_type, label, region"'
+
+# TODO: topic of changes
+- name: setup create the server
+ ngine_io.vultr.vultr_server:
+ name: "{{ vultr_server_name }}"
+ os: "{{ vultr_server_os }}"
+ plan: "{{ vultr_server_plan }}"
+ region: New Jersey
+ register: server
+
+- name: test create reserved ip in check mode
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ register: result
+ check_mode: true
+- name: verify test create reserved ip in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create reserved ip
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ register: result
+- name: verify test create reserved ip
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - not result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet is defined
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test create reserved ip idempotence
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ register: result
+- name: verify test create reserved ip idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - not result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet is defined
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test attach instance of reserved ip in check mode
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ instance_name: "{{ vultr_server_name }}"
+ register: result
+ check_mode: true
+- name: verify test detach instance of reserved ip in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - not result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test attach instance of reserved ip
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ instance_name: "{{ vultr_server_name }}"
+ register: result
+- name: verify test attach instance of reserved ip
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test attach instance of reserved ip idempotence
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ instance_name: "{{ vultr_server_name }}"
+ register: result
+- name: verify test attach instance of reserved ip idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test ignore instance attached reserved ip idempotence
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ register: result
+- name: verify test test ignore instance attached reserved ip idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test detach instance of reserved ip in check mode
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ instance_id: ""
+ register: result
+ check_mode: true
+- name: verify test detach instance of reserved ip in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test detach instance of reserved ip
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ instance_id: ""
+ register: result
+- name: verify test detach instance of reserved ip
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - not result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test detach instance of reserved ip idempotence
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ instance_id: ""
+ register: result
+- name: verify test detach instance of reserved ip idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - not result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test absent reserved ip in check mode
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test absent reserved ip in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - not result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test absent reserved ip
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ state: absent
+ register: result
+- name: verify test absent reserved ip
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - result.vultr_reserved_ip.label == vultr_reserved_ip_name
+ - not result.vultr_reserved_ip.instance_id
+ - result.vultr_reserved_ip.subnet
+ - result.vultr_reserved_ip.ip_type == 'v4'
+
+- name: test absent reserved ip idempotence
+ vultr.cloud.reserved_ip:
+ label: "{{ vultr_reserved_ip_name }}"
+ ip_type: v4
+ region: ewr
+ state: absent
+ register: result
+- name: verify test absent reserved ip idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+
+# TODO: topic of changes
+- name: cleanup the server
+ ngine_io.vultr.vultr_server:
+ name: "{{ vultr_server_name }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/defaults/main.yml
new file mode 100644
index 000000000..d6566f839
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/defaults/main.yml
@@ -0,0 +1,15 @@
+# Copyright (c) 2023, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_instance:
+ label: "snap1"
+ plan: vc2-1c-1gb
+ region: ams
+ os: Debian 11 x64 (bullseye)
+
+vultr_snapshots:
+ - description: "{{ vultr_resource_prefix }}_desc1"
+ instance: "{{ vultr_instance.label }}"
+
+ - description: "{{ vultr_resource_prefix }}_desc2"
+ url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.raw
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/absent.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/absent.yml
new file mode 100644
index 000000000..ee0ac4e6b
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/absent.yml
@@ -0,0 +1,35 @@
+---
+- name: snapshot info
+ ansible.builtin.debug:
+ var: snapshot
+
+- name: test absent snapshot in check mode
+ vultr.cloud.snapshot:
+ description: "{{ snapshot.description }}"
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test absent snapshot in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test absent snapshot
+ vultr.cloud.snapshot:
+ description: "{{ snapshot.description }}"
+ state: absent
+ register: result
+- name: verify test absent snapshot
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test absent snapshot idempotence
+ vultr.cloud.snapshot:
+ description: "{{ snapshot.description }}"
+ state: absent
+ register: result
+- name: verify test absent snapshot idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/failures.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/failures.yml
new file mode 100644
index 000000000..d186fc67a
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/failures.yml
@@ -0,0 +1,33 @@
+---
+- name: test fail if missing arguments
+ vultr.cloud.snapshot:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing arguments
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: description"'
+
+- name: test fail if missing arguments required one of
+ vultr.cloud.snapshot:
+ description: my snapshot
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing arguments required one of
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - '"one of the following required" in result.msg'
+
+- name: test fail if instance not found
+ vultr.cloud.snapshot:
+ description: my snapshot
+ instance: does-not-exist
+ register: result
+ ignore_errors: true
+- name: verify test fail if instance not found
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - '"No Resource /instances with label found: does-not-exist" in result.msg'
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/main.yml
new file mode 100644
index 000000000..aa29bdb94
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/main.yml
@@ -0,0 +1,10 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_snapshot
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_instance
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/present.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/present.yml
new file mode 100644
index 000000000..ee2aed1d4
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/present.yml
@@ -0,0 +1,36 @@
+---
+- name: test create snapshot in check mode
+ vultr.cloud.snapshot:
+ description: "{{ snapshot.description }}"
+ instance: "{{ snapshot.instance | default(omit) }}"
+ url: "{{ snapshot.url | default(omit) }}"
+ register: result
+ check_mode: true
+- name: verify test create snapshot in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create snapshot
+ vultr.cloud.snapshot:
+ description: "{{ snapshot.description }}"
+ instance: "{{ snapshot.instance | default(omit) }}"
+ url: "{{ snapshot.url | default(omit) }}"
+ register: result
+- name: verify test create snapshot
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_snapshot.description == snapshot.description
+
+- name: test create snapshot idempotence
+ vultr.cloud.snapshot:
+ description: "{{ snapshot.description }}"
+ instance: "{{ snapshot.instance | default(omit) }}"
+ url: "{{ snapshot.url | default(omit) }}"
+ register: result
+- name: verify test create snapshot idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_snapshot.description == snapshot.description
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/tests.yml
new file mode 100644
index 000000000..6ed8a5a98
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot/tasks/tests.yml
@@ -0,0 +1,35 @@
+# Copyright (c) 2023, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup
+ vultr.cloud.snapshot:
+ description: "{{ snapshot.description }}"
+ state: absent
+ with_items: "{{ vultr_snapshots }}"
+ loop_control:
+ loop_var: snapshot
+
+- ansible.builtin.import_tasks: failures.yml
+
+- name: setup instance
+ vultr.cloud.instance:
+ label: "{{ vultr_instance.label }}"
+ plan: "{{ vultr_instance.plan }}"
+ region: "{{ vultr_instance.region }}"
+ os: "{{ vultr_instance.os }}"
+
+- ansible.builtin.include_tasks: present.yml
+ with_items: "{{ vultr_snapshots }}"
+ loop_control:
+ loop_var: snapshot
+
+- ansible.builtin.include_tasks: absent.yml
+ with_items: "{{ vultr_snapshots }}"
+ loop_control:
+ loop_var: snapshot
+
+- name: cleanup instance
+ vultr.cloud.instance:
+ label: "{{ vultr_instance.label }}"
+ region: "{{ vultr_instance.region }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/defaults/main.yml
new file mode 100644
index 000000000..d79abfafd
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+vultr_snapshot_description: "{{ vultr_resource_prefix }}_snap_info"
+vultr_snapshot_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.raw
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/tasks/main.yml
new file mode 100644
index 000000000..55bffd3ee
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_snapshot
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/tasks/tests.yml
new file mode 100644
index 000000000..fe7a195ce
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/snapshot_info/tasks/tests.yml
@@ -0,0 +1,34 @@
+# Copyright (c) 2023, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test gather snapshot info - empty resources
+ vultr.cloud.snapshot_info:
+
+- name: Create the snapshot
+ vultr.cloud.snapshot:
+ description: "{{ vultr_snapshot_description }}"
+ url: "{{ vultr_snapshot_url }}"
+
+- name: test gather snapshot info in check mode
+ vultr.cloud.snapshot_info:
+ check_mode: true
+ register: result
+
+- name: verify test gather vultr snapshot info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_snapshot_info|selectattr('description','equalto','{{ vultr_snapshot_description }}') | list | count == 1
+
+- name: test gather snapshot info
+ vultr.cloud.snapshot_info:
+ register: result
+
+- name: verify test gather vultr snapshot info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_snapshot_info|selectattr('description','equalto','{{ vultr_snapshot_description }}') | list | count == 1
+
+- name: Delete the snapshot
+ vultr.cloud.snapshot:
+ name: "{{ vultr_snapshot_description }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/defaults/main.yml
new file mode 100644
index 000000000..14ed4d86e
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/defaults/main.yml
@@ -0,0 +1,6 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_ssh_key_name: "{{ vultr_resource_prefix }}_ansible-ssh-key"
+vultr_ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAyWYItY+3w5b8PdGRoz0oY5mufqydW96naE+VM3JSvJFAUS08rAjQQpQ03ymoALeHQy6JVZbcgecxn6p0pAOINQdqufn4udPtOPCtMjNiPGpkSM9ah/6X5+kvyWMNrvlf+Ld4OOoszP5sAkgQzIbrFQAm41XknBUha0zkewZwfrVhain4pnDjV7wCcChId/Q/Gbi4xMtXkisznWcAJcueBs3EEZDKhJ5q0VeWSJEhYJDLFN1sOxF0AIUnMrOhfKQ/LjgREXPB6uCl899INUTXRNNjRpeMXyJ2wMMmOAbua2qEd1r13Bu1n+6A823Hzb33fyMXuqWnJwBJ4DCvMlGuEsfuOK+xk7DaBfLHbcM6fsPk0/4psTE6YLgC41remr6+u5ZWsY/faMtSnNPie8Z8Ov0DIYGdhbJjUXk1HomxRV9+ZfZ2Ob8iCwlaAQAyEUM6fs3Kxt8pBD8dx1HOkhsfBWPvuDr5y+kqE7H8/MuPDTc0QgH2pjUMpmw/XBwNDHshVEjrZvtICOjOLUJxcowLO1ivNYwPwowQxfisMy56LfYdjsOslBiqsrkAqvNGm1zu8wKHeqVN9w5l3yUELpvubfm9NKIvYcl6yWF36T0c5vE+g0DU/Jy4XpTj0hZG9QV2mRQcLJnd2pxQtJT7cPFtrn/+tgRxzjEtbDXummDV4sE= ansible@example.com"
+vultr_ssh_key2: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCoQ9S7V+CufAgwoehnf2TqsJ9LTsu8pUA3FgpS2mdVwcMcTs++8P5sQcXHLtDmNLpWN4k7NQgxaY1oXy5e25x/4VhXaJXWEt3luSw+Phv/PB2+aGLvqCUirsLTAD2r7ieMhd/pcVf/HlhNUQgnO1mupdbDyqZoGD/uCcJiYav8i/V7nJWJouHA8yq31XS2yqXp9m3VC7UZZHzUsVJA9Us5YqF0hKYeaGruIHR2bwoDF9ZFMss5t6/pzxMljU/ccYwvvRDdI7WX4o4+zLuZ6RWvsU6LGbbb0pQdB72tlV41fSefwFsk4JRdKbyV3Xjf25pV4IXOTcqhy+4JTB/jXxrF torwalds@github.com"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/tasks/main.yml
new file mode 100644
index 000000000..44b1abf0b
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_ssh_key
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/tasks/tests.yml
new file mode 100644
index 000000000..4b9ba76bd
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key/tasks/tests.yml
@@ -0,0 +1,140 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ state: absent
+ register: result
+- name: verify setup
+ ansible.builtin.assert:
+ that:
+ - result is success
+
+- name: test fail if missing name
+ vultr.cloud.ssh_key:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing name
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: name"'
+
+- name: test fail if missing params for state=present
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ register: result
+ ignore_errors: true
+- name: verify fail if missing params for state=present
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "state is present but all of the following are missing: ssh_key"'
+
+- name: test create ssh key in check mode
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ ssh_key: "{{ vultr_ssh_key }}"
+ register: result
+ check_mode: true
+- name: verify test create ssh key in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create ssh key
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ ssh_key: "{{ vultr_ssh_key }}"
+ register: result
+- name: verify test create ssh key
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_ssh_key.name == vultr_ssh_key_name
+ - result.vultr_ssh_key.ssh_key == vultr_ssh_key
+
+- name: test create ssh key idempotence
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ ssh_key: "{{ vultr_ssh_key }}"
+ register: result
+- name: verify test create ssh key idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_ssh_key.name == vultr_ssh_key_name
+ - result.vultr_ssh_key.ssh_key == vultr_ssh_key
+
+- name: test update ssh key in check mode
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ ssh_key: "{{ vultr_ssh_key2 }}"
+ register: result
+ check_mode: true
+- name: verify test update ssh key in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_ssh_key.name == vultr_ssh_key_name
+ - result.vultr_ssh_key.ssh_key == vultr_ssh_key
+
+- name: test update ssh key
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ ssh_key: "{{ vultr_ssh_key2 }}"
+ register: result
+- name: verify test update ssh key
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_ssh_key.name == vultr_ssh_key_name
+ - result.vultr_ssh_key.ssh_key == vultr_ssh_key2
+
+- name: test update ssh key idempotence
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ ssh_key: "{{ vultr_ssh_key2 }}"
+ register: result
+- name: verify test update ssh key idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_ssh_key.name == vultr_ssh_key_name
+ - result.vultr_ssh_key.ssh_key == vultr_ssh_key2
+
+- name: test absent ssh key in check mode
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test absent ssh key in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_ssh_key.name == vultr_ssh_key_name
+ - result.vultr_ssh_key.ssh_key == vultr_ssh_key2
+
+- name: test absent ssh key
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ state: absent
+ register: result
+- name: verify test absent ssh key
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_ssh_key.name == vultr_ssh_key_name
+ - result.vultr_ssh_key.ssh_key == vultr_ssh_key2
+
+- name: test absent ssh key idempotence
+ vultr.cloud.ssh_key:
+ name: "{{ vultr_ssh_key_name }}"
+ state: absent
+ register: result
+- name: verify test absent ssh key idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/defaults/main.yml
new file mode 100644
index 000000000..914be3a6e
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+ssh_key_name: "{{ vultr_resource_prefix }}-sshkey"
+ssh_key_content: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+ZFQv3MyjtL1BMpSA0o0gIkzLVVC711rthT29hBNeORdNowQ7FSvVWUdAbTq00U7Xzak1ANIYLJyn+0r7olsdG4XEiUR0dqgC99kbT/QhY5mLe5lpl7JUjW9ctn00hNmt+TswpatCKWPNwdeAJT2ERynZaqPobENgvIq7jfOFWQIVew7qrewtqwerqwrewUr2Cdq7Nb7U0XFXh3x1p0v0+MbL4tiJwPlMAGvFTKIMt+EaA+AsRIxiOo9CMk5ZuOl9pT8h5vNuEOcvS0qx4v44EAD2VOsCVCcrPNMcpuSzZP8dRTGU9wRREAWXngD0Zq9YJMH38VTxHiskoBw1NnPz ansibletest-{{ vultr_resource_prefix }}@sshkey
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/tasks/main.yml
new file mode 100644
index 000000000..44b1abf0b
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_ssh_key
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/tasks/tests.yml
new file mode 100644
index 000000000..63ce48ee0
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/ssh_key_info/tasks/tests.yml
@@ -0,0 +1,44 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test get vultr ssh key info - empty resources
+ vultr.cloud.ssh_key_info:
+ register: result
+
+- name: verify test get vultr ssh key infos in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_ssh_key_info|selectattr('name','equalto','{{ ssh_key_name }}') | list | count == 0
+ - result.vultr_ssh_key_info|selectattr('ssh_key','equalto','{{ ssh_key_content }}') | list | count == 0
+
+- name: Upload an ssh key
+ vultr.cloud.ssh_key:
+ name: "{{ ssh_key_name }}"
+ ssh_key: "{{ ssh_key_content }}"
+
+- name: test get vultr ssh key infos in check mode
+ vultr.cloud.ssh_key_info:
+ check_mode: true
+ register: result
+
+- name: verify test get vultr ssh key infos in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_ssh_key_info|selectattr('name','equalto','{{ ssh_key_name }}') | list | count == 1
+ - result.vultr_ssh_key_info|selectattr('ssh_key','equalto','{{ ssh_key_content }}') | list | count == 1
+
+- name: test get vultr ssh key info
+ vultr.cloud.ssh_key_info:
+ register: result
+
+- name: verify test get vultr ssh key infos
+ ansible.builtin.assert:
+ that:
+ - result.vultr_ssh_key_info|selectattr('name','equalto','{{ ssh_key_name }}') | list | count == 1
+ - result.vultr_ssh_key_info|selectattr('ssh_key','equalto','{{ ssh_key_content }}') | list | count == 1
+
+- name: Destroy the ssh key
+ vultr.cloud.ssh_key:
+ name: "{{ ssh_key_name }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/defaults/main.yml
new file mode 100644
index 000000000..3093aa725
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/defaults/main.yml
@@ -0,0 +1,6 @@
+# Copyright (c) 2018, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_startup_script_name: "{{ vultr_resource_prefix }}_script"
+vultr_startup_script: "#!/bin/bash\necho Hello World > /root/hello"
+vultr_startup_script2: "#!/bin/bash\necho Hello to my World > /root/hello"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/tasks/main.yml
new file mode 100644
index 000000000..18bc711e7
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_startup_script
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/tasks/tests.yml
new file mode 100644
index 000000000..cd8b067ee
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script/tasks/tests.yml
@@ -0,0 +1,140 @@
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ state: absent
+ register: result
+- name: verify setup
+ ansible.builtin.assert:
+ that:
+ - result is success
+
+- name: test fail if missing name
+ vultr.cloud.startup_script:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing name
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: name"'
+
+- name: test fail if missing params for state=present
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ register: result
+ ignore_errors: true
+- name: verify fail if missing params for state=present
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "state is present but all of the following are missing: script"'
+
+- name: test create startup script in check mode
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ script: "{{ vultr_startup_script }}"
+ register: result
+ check_mode: true
+- name: verify test create startup script in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create startup script
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ script: "{{ vultr_startup_script }}"
+ register: result
+- name: verify test create startup script
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_startup_script.name == vultr_startup_script_name
+ - result.vultr_startup_script.script == vultr_startup_script
+
+- name: test create startup script idempotence
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ script: "{{ vultr_startup_script }}"
+ register: result
+- name: verify test create startup script idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_startup_script.name == vultr_startup_script_name
+ - result.vultr_startup_script.script == vultr_startup_script
+
+- name: test update startup script in check mode
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ script: "{{ vultr_startup_script2 }}"
+ register: result
+ check_mode: true
+- name: verify test update startup script in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_startup_script.name == vultr_startup_script_name
+ - result.vultr_startup_script.script == vultr_startup_script
+
+- name: test update startup script
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ script: "{{ vultr_startup_script2 }}"
+ register: result
+- name: verify test update startup script
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_startup_script.name == vultr_startup_script_name
+ - result.vultr_startup_script.script == vultr_startup_script2
+
+- name: test update startup script idempotence
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ script: "{{ vultr_startup_script2 }}"
+ register: result
+- name: verify test update startup script idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_startup_script.name == vultr_startup_script_name
+ - result.vultr_startup_script.script == vultr_startup_script2
+
+- name: test absent startup script in check mode
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test absent startup script in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_startup_script.name == vultr_startup_script_name
+ - result.vultr_startup_script.script == vultr_startup_script2
+
+- name: test absent startup script
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ state: absent
+ register: result
+- name: verify test absent startup script
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_startup_script.name == vultr_startup_script_name
+ - result.vultr_startup_script.script == vultr_startup_script2
+
+- name: test absent startup script idempotence
+ vultr.cloud.startup_script:
+ name: "{{ vultr_startup_script_name }}"
+ state: absent
+ register: result
+- name: verify test absent startup script idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/defaults/main.yml
new file mode 100644
index 000000000..37632d6eb
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/defaults/main.yml
@@ -0,0 +1,4 @@
+---
+startup_script_name: "{{ vultr_resource_prefix }}_script"
+startup_script_type: boot
+startup_script_content: "#!/bin/bash\necho Hello World > /root/hello"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/tasks/main.yml
new file mode 100644
index 000000000..18bc711e7
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_startup_script
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/tasks/tests.yml
new file mode 100644
index 000000000..730df6d71
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/startup_script_info/tasks/tests.yml
@@ -0,0 +1,35 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test gather vultr startup script info - empty resources
+ vultr.cloud.startup_script_info:
+
+- name: Create the script
+ vultr.cloud.startup_script:
+ name: "{{ startup_script_name }}"
+ script_type: "{{ startup_script_type }}"
+ script: "{{ startup_script_content }}"
+
+- name: test gather vultr startup script info in check mode
+ vultr.cloud.startup_script_info:
+ check_mode: true
+ register: result
+
+- name: verify test gather vultr startup script info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_startup_script_info|selectattr('name','equalto','{{ startup_script_name }}') | list | count == 1
+
+- name: test gather vultr startup script info
+ vultr.cloud.startup_script_info:
+ register: result
+
+- name: verify test gather vultr startup script info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_startup_script_info|selectattr('name','equalto','{{ startup_script_name }}') | list | count == 1
+
+- name: Delete the script
+ vultr.cloud.startup_script:
+ name: "{{ startup_script_name }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/user/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/user/defaults/main.yml
new file mode 100644
index 000000000..a95c755d3
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user/defaults/main.yml
@@ -0,0 +1,4 @@
+# Copyright (c) 2018, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+vultr_user_name: "{{ vultr_resource_prefix }}_user"
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/user/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/user/tasks/main.yml
new file mode 100644
index 000000000..bd6ae3f26
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_user
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/user/tasks/tests.yml
new file mode 100644
index 000000000..06bb2b843
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user/tasks/tests.yml
@@ -0,0 +1,218 @@
+---
+# Copyright (c) 2018, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+- name: setup
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ state: absent
+ register: result
+- name: verify setup
+ ansible.builtin.assert:
+ that:
+ - result is success
+
+- name: test fail if missing name
+ vultr.cloud.user:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing name
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: name"'
+
+- name: test fail if missing params for state=present
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ register: result
+ ignore_errors: true
+- name: verify fail if missing params for state=present
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg.startswith("state is present but all of the following are missing")'
+
+- name: test fail param not in choices
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ email: john.doe{{ vultr_resource_prefix }}@example.com
+ password: s3cr3t
+ acls:
+ - bad
+ - dns
+ - manage_users
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing name
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg.startswith("value of acls must be one or more of")'
+
+- name: test create user in check mode
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ email: john.doe{{ vultr_resource_prefix }}@example.com
+ password: s3cr3t
+ acls:
+ - upgrade
+ - dns
+ - manage_users
+ register: result
+ check_mode: true
+- name: verify test create user in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create user
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ email: john.doe{{ vultr_resource_prefix }}@example.com
+ password: s3cr3t
+ acls:
+ - upgrade
+ - dns
+ - manage_users
+ register: result
+- name: verify test create user
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_user.name == vultr_user_name
+ - result.vultr_user.email == 'john.doe{{ vultr_resource_prefix }}@example.com'
+ - result.vultr_user.api_enabled == true
+ - "'upgrade' in result.vultr_user.acls"
+ - "'manage_users' in result.vultr_user.acls"
+ - "'dns' in result.vultr_user.acls"
+
+- name: test create user idempotence
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ email: john.doe{{ vultr_resource_prefix }}@example.com
+ password: s3cr3t
+ acls:
+ - upgrade
+ - dns
+ - manage_users
+ register: result
+- name: verify test create user idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_user.name == vultr_user_name
+ - result.vultr_user.email == 'john.doe{{ vultr_resource_prefix }}@example.com'
+ - result.vultr_user.api_enabled == true
+ - "'upgrade' in result.vultr_user.acls"
+ - "'manage_users' in result.vultr_user.acls"
+ - "'dns' in result.vultr_user.acls"
+
+- name: test update user in check mode
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ email: jimmy{{ vultr_resource_prefix }}@example.com
+ password: s3cr3t
+ api_enabled: false
+ acls:
+ - manage_users
+ - upgrade
+ - support
+ register: result
+ check_mode: true
+- name: verify test update user in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_user.name == vultr_user_name
+ - result.vultr_user.email == 'john.doe{{ vultr_resource_prefix }}@example.com'
+ - "'upgrade' in result.vultr_user.acls"
+ - "'manage_users' in result.vultr_user.acls"
+ - "'dns' in result.vultr_user.acls"
+ - result.vultr_user.api_enabled == true
+
+- name: test update user
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ email: jimmy{{ vultr_resource_prefix }}@example.com
+ password: s3cr3t
+ api_enabled: false
+ acls:
+ - manage_users
+ - upgrade
+ - support
+ register: result
+- name: verify test update user
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_user.name == vultr_user_name
+ - result.vultr_user.email == 'jimmy{{ vultr_resource_prefix }}@example.com'
+ - "'upgrade' in result.vultr_user.acls"
+ - "'manage_users' in result.vultr_user.acls"
+ - "'support' in result.vultr_user.acls"
+ - result.vultr_user.api_enabled == false
+
+- name: test update user idempotence
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ email: jimmy{{ vultr_resource_prefix }}@example.com
+ password: s3cr3t
+ api_enabled: false
+ acls:
+ - manage_users
+ - upgrade
+ - support
+ register: result
+- name: verify test update user idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_user.name == vultr_user_name
+ - result.vultr_user.email == 'jimmy{{ vultr_resource_prefix }}@example.com'
+ - "'upgrade' in result.vultr_user.acls"
+ - "'manage_users' in result.vultr_user.acls"
+ - "'support' in result.vultr_user.acls"
+ - result.vultr_user.api_enabled == false
+
+- name: test absent user in check mode
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test absent user in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_user.name == vultr_user_name
+ - result.vultr_user.email == 'jimmy{{ vultr_resource_prefix }}@example.com'
+ - "'upgrade' in result.vultr_user.acls"
+ - "'manage_users' in result.vultr_user.acls"
+ - "'support' in result.vultr_user.acls"
+ - result.vultr_user.api_enabled == false
+
+- name: test absent user
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ state: absent
+ register: result
+- name: verify test absent user
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_user.name == vultr_user_name
+ - result.vultr_user.email == 'jimmy{{ vultr_resource_prefix }}@example.com'
+ - "'upgrade' in result.vultr_user.acls"
+ - "'manage_users' in result.vultr_user.acls"
+ - "'support' in result.vultr_user.acls"
+ - result.vultr_user.api_enabled == false
+
+- name: test absent user idempotence
+ vultr.cloud.user:
+ name: "{{ vultr_user_name }}"
+ state: absent
+ register: result
+- name: verify test absent user idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/defaults/main.yml
new file mode 100644
index 000000000..5922f6fe2
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/defaults/main.yml
@@ -0,0 +1,10 @@
+---
+vultr_resource_prefix: "vultr-test-prefix"
+user_name: "{{ vultr_resource_prefix }}_user"
+user_email: mytestuser-{{ vultr_resource_prefix }}@example.com
+user_password: "{{ vultr_resource_prefix }}aP4ssw0rd!"
+user_acls:
+ - upgrade
+ - dns
+ - manage_users
+ - subscriptions
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user_info/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/tasks/main.yml
new file mode 100644
index 000000000..bd6ae3f26
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_user
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/user_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/tasks/tests.yml
new file mode 100644
index 000000000..023cd3b82
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/user_info/tasks/tests.yml
@@ -0,0 +1,34 @@
+# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
+# Copyright (c) 2021, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: Create the user
+ vultr.cloud.user:
+ name: "{{ user_name }}"
+ email: "{{ user_email }}"
+ password: "{{ user_password }}"
+ acls: "{{ user_acls }}"
+
+- name: test get vultr user info in check mode
+ vultr.cloud.user_info:
+ register: result
+ check_mode: true
+
+- name: verify test get vultr user info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_user_info|selectattr('name','equalto','{{ user_name }}') | list | count == 1
+
+- name: test get vultr user info
+ vultr.cloud.user_info:
+ register: result
+
+- name: verify test get vultr user info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_user_info|selectattr('name','equalto','{{ user_name }}') | list | count == 1
+
+- name: Delete the user
+ vultr.cloud.user:
+ name: "{{ user_name }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/defaults/main.yml
new file mode 100644
index 000000000..83923ffe8
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+vultr_vpc_description: "{{ vultr_resource_prefix }}_vpc"
+vultr_vpc_v4_subnet: 192.168.42.0
+vultr_vpc_v4_subnet_mask: 24
+vultr_vpc_region: ewr
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/tasks/main.yml
new file mode 100644
index 000000000..4a0ba389c
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_vpc
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/tasks/tests.yml
new file mode 100644
index 000000000..8ed2dfdc7
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc/tasks/tests.yml
@@ -0,0 +1,112 @@
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: setup
+ vultr.cloud.vpc:
+ description: "{{ vultr_vpc_description }}"
+ state: absent
+
+- name: test fail if missing description
+ vultr.cloud.vpc:
+ register: result
+ ignore_errors: true
+- name: verify test fail if missing description
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "missing required arguments: description"'
+
+- name: test fail if missing params for state=present
+ vultr.cloud.vpc:
+ description: "{{ vultr_vpc_description }}"
+ register: result
+ ignore_errors: true
+- name: verify fail if missing params for state=present
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - 'result.msg == "state is present but all of the following are missing: v4_subnet, v4_subnet_mask, region"'
+
+- name: test create vpc in check mode
+ vultr.cloud.vpc:
+ description: "{{ vultr_vpc_description }}"
+ v4_subnet: "{{ vultr_vpc_v4_subnet }}"
+ v4_subnet_mask: "{{ vultr_vpc_v4_subnet_mask }}"
+ region: "{{ vultr_vpc_region }}"
+ register: result
+ check_mode: true
+- name: verify test create server in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+
+- name: test create vpc
+ vultr.cloud.vpc:
+ description: "{{ vultr_vpc_description }}"
+ v4_subnet: "{{ vultr_vpc_v4_subnet }}"
+ v4_subnet_mask: "{{ vultr_vpc_v4_subnet_mask }}"
+ region: "{{ vultr_vpc_region }}"
+ register: result
+- name: verify test create vpc
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_vpc.description == vultr_vpc_description
+ - result.vultr_vpc.region == vultr_vpc_region
+ - result.vultr_vpc.v4_subnet == vultr_vpc_v4_subnet
+ - result.vultr_vpc.v4_subnet_mask == vultr_vpc_v4_subnet_mask
+
+- name: test create vpc idempotence
+ vultr.cloud.vpc:
+ description: "{{ vultr_vpc_description }}"
+ v4_subnet: "{{ vultr_vpc_v4_subnet }}"
+ v4_subnet_mask: "{{ vultr_vpc_v4_subnet_mask }}"
+ region: "{{ vultr_vpc_region }}"
+ register: result
+- name: verify test vpc idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.vultr_vpc.description == vultr_vpc_description
+ - result.vultr_vpc.region == vultr_vpc_region
+ - result.vultr_vpc.v4_subnet == vultr_vpc_v4_subnet
+ - result.vultr_vpc.v4_subnet_mask == vultr_vpc_v4_subnet_mask
+
+- name: test destroy vpc in check mode
+ vultr.cloud.vpc:
+ description: "{{ vultr_vpc_description }}"
+ state: absent
+ register: result
+ check_mode: true
+- name: verify test destroy vpc in check mode
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_vpc.description == vultr_vpc_description
+ - result.vultr_vpc.region == vultr_vpc_region
+ - result.vultr_vpc.v4_subnet == vultr_vpc_v4_subnet
+ - result.vultr_vpc.v4_subnet_mask == vultr_vpc_v4_subnet_mask
+
+- name: test destroy vpc
+ vultr.cloud.vpc:
+ description: "{{ vultr_vpc_description }}"
+ state: absent
+ register: result
+- name: verify test destroy vpc
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.vultr_vpc.description == vultr_vpc_description
+ - result.vultr_vpc.region == vultr_vpc_region
+ - result.vultr_vpc.v4_subnet == vultr_vpc_v4_subnet
+ - result.vultr_vpc.v4_subnet_mask == vultr_vpc_v4_subnet_mask
+
+- name: test destroy an existing vpc idempotence
+ vultr.cloud.vpc:
+ description: "{{ vultr_vpc_description }}"
+ state: absent
+ register: result
+- name: verify test destroy an existing vpc idempotence
+ ansible.builtin.assert:
+ that:
+ - result is not changed
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/aliases b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/aliases
new file mode 100644
index 000000000..c749ce7ca
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/aliases
@@ -0,0 +1,3 @@
+cloud/vultr
+needs/target/common
+needs/target/cleanup
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/defaults/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/defaults/main.yml
new file mode 100644
index 000000000..83923ffe8
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+vultr_vpc_description: "{{ vultr_resource_prefix }}_vpc"
+vultr_vpc_v4_subnet: 192.168.42.0
+vultr_vpc_v4_subnet_mask: 24
+vultr_vpc_region: ewr
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/meta/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/meta/main.yml
new file mode 100644
index 000000000..2083f0e12
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - common
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/tasks/main.yml b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/tasks/main.yml
new file mode 100644
index 000000000..4a0ba389c
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- block:
+ - ansible.builtin.import_tasks: tests.yml
+ always:
+ - ansible.builtin.import_role:
+ name: cleanup
+ tasks_from: cleanup_vpc
diff --git a/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/tasks/tests.yml b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/tasks/tests.yml
new file mode 100644
index 000000000..a8ab3d857
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/integration/targets/vpc_info/tasks/tests.yml
@@ -0,0 +1,36 @@
+# Copyright (c) 2022, René Moser <mail@renemoser.net>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+---
+- name: test gather VPC info - empty resources
+ vultr.cloud.vpc_info:
+
+- name: Create the vpc
+ vultr.cloud.vpc:
+ description: "{{ vultr_vpc_description }}"
+ v4_subnet: "{{ vultr_vpc_v4_subnet }}"
+ v4_subnet_mask: "{{ vultr_vpc_v4_subnet_mask }}"
+ region: "{{ vultr_vpc_region }}"
+
+- name: test gather VPC info in check mode
+ vultr.cloud.vpc_info:
+ check_mode: true
+ register: result
+
+- name: verify test gather vultr vpc info in check mode
+ ansible.builtin.assert:
+ that:
+ - result.vultr_vpc_info|selectattr('description','equalto','{{ vultr_vpc_description }}') | list | count == 1
+
+- name: test gather VPC info
+ vultr.cloud.vpc_info:
+ register: result
+
+- name: verify test gather vultr vpc info
+ ansible.builtin.assert:
+ that:
+ - result.vultr_vpc_info|selectattr('description','equalto','{{ vultr_vpc_description }}') | list | count == 1
+
+- name: Delete the VPC
+ vultr.cloud.vpc:
+ name: "{{ vultr_vpc_description }}"
+ state: absent
diff --git a/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/empty_vultr_inventory.json b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/empty_vultr_inventory.json
new file mode 100644
index 000000000..4ae585950
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/empty_vultr_inventory.json
@@ -0,0 +1,10 @@
+{
+ "instances": [],
+ "meta": {
+ "total": 0,
+ "links": {
+ "next": "",
+ "prev": ""
+ }
+ }
+}
diff --git a/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/unauthorized_vultr_inventory.json b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/unauthorized_vultr_inventory.json
new file mode 100644
index 000000000..8da6d1321
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/unauthorized_vultr_inventory.json
@@ -0,0 +1,4 @@
+{
+ "error": "Invalid API token.",
+ "status": 401
+}
diff --git a/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory.json b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory.json
new file mode 100644
index 000000000..11ae1c749
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory.json
@@ -0,0 +1,275 @@
+[
+ {
+ "id": "f1c4ae0c-ea06-4449-a028-ffe6b05f9f80",
+ "os": "Custom Installed",
+ "ram": 512,
+ "disk": 10,
+ "main_ip": "100.68.102.38",
+ "vcpu_count": 1,
+ "region": "ewr",
+ "plan": "vc2-1c-0.5gb-v6",
+ "date_created": "2022-12-05T13:15:58+00:00",
+ "status": "active",
+ "allowed_bandwidth": 500,
+ "netmask_v4": "255.255.192.0",
+ "gateway_v4": "100.68.64.1",
+ "power_status": "running",
+ "server_status": "locked",
+ "v6_network": "2001:19f0:face:395c::",
+ "v6_main_ip": "2001:19f0:face:395c:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "",
+ "internal_ip": "10.1.96.3",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "",
+ "tag": "",
+ "tags": [],
+ "os_id": 159,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": [
+ "auto_backups",
+ "ipv6",
+ "ddos_protection"
+ ]
+ },
+ {
+ "id": "4adbf858-8426-40c4-8f48-91d83024bb5e",
+ "os": "Custom Installed",
+ "ram": 1024,
+ "disk": 25,
+ "main_ip": "100.68.102.39",
+ "vcpu_count": 1,
+ "region": "sea",
+ "plan": "vc2-1c-1gb",
+ "date_created": "2022-12-05T13:21:57+00:00",
+ "status": "active",
+ "allowed_bandwidth": 1000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "104.207.156.1",
+ "power_status": "stopped",
+ "server_status": "locked",
+ "v6_network": "2001:19f0:face:f17::",
+ "v6_main_ip": "2001:19f0:face:0f17:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "restore-guest",
+ "internal_ip": "",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "restore-guest",
+ "tag": "",
+ "tags": [],
+ "os_id": 159,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": [
+ "ipv6"
+ ]
+ },
+ {
+ "id": "5d8813ec-df65-4a69-8bfc-864aabe2a7d2",
+ "os": "Custom Installed",
+ "ram": 1024,
+ "disk": 25,
+ "main_ip": "100.68.102.40",
+ "vcpu_count": 1,
+ "region": "ord",
+ "plan": "vhp-1c-1gb-intel",
+ "date_created": "2022-12-05T13:29:19+00:00",
+ "status": "pending",
+ "allowed_bandwidth": 2000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "45.76.228.1",
+ "power_status": "running",
+ "server_status": "none",
+ "v6_network": "",
+ "v6_main_ip": "",
+ "v6_network_size": 0,
+ "label": "snapshot-guest",
+ "internal_ip": "",
+ "kvm": "",
+ "hostname": "snapshot-guest",
+ "tag": "",
+ "tags": [],
+ "os_id": 159,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": []
+ },
+ {
+ "id": "30c17c34-223f-436e-acbe-393af5293adb",
+ "os": "Debian 11 x64 (bullseye)",
+ "ram": 512,
+ "disk": 10,
+ "main_ip": "100.68.102.41",
+ "vcpu_count": 1,
+ "region": "ewr",
+ "plan": "vc2-1c-0.5gb-v6",
+ "date_created": "2022-12-05T12:43:00+00:00",
+ "status": "active",
+ "allowed_bandwidth": 500,
+ "netmask_v4": "255.255.192.0",
+ "gateway_v4": "100.68.64.1",
+ "power_status": "running",
+ "server_status": "ok",
+ "v6_network": "2001:19f0:face:8fd::",
+ "v6_main_ip": "2001:19f0:face:08fd:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "debian-guest",
+ "internal_ip": "10.1.96.3",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "debian-guest",
+ "tag": "",
+ "tags": [
+ "vpc",
+ "vpc:d0db548b-5d50-4c94-9cdb-b083d46925f8",
+ "os:debian"
+ ],
+ "os_id": 477,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": [
+ "auto_backups",
+ "ipv6"
+ ]
+ },
+ {
+ "id": "37d67f9f-17f0-4c56-879b-507355dc5174",
+ "os": "OpenBSD 7.2 x64",
+ "ram": 4096,
+ "disk": 30,
+ "main_ip": "100.68.102.42",
+ "vcpu_count": 1,
+ "region": "ewr",
+ "plan": "voc-g-1c-4gb-30s-amd",
+ "date_created": "2022-12-05T12:44:17+00:00",
+ "status": "active",
+ "allowed_bandwidth": 4000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "45.63.22.1",
+ "power_status": "running",
+ "server_status": "ok",
+ "v6_network": "",
+ "v6_main_ip": "",
+ "v6_network_size": 0,
+ "label": "openbsd-guest",
+ "internal_ip": "",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "openbsd-guest",
+ "tag": "",
+ "tags": [],
+ "os_id": 1968,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": []
+ },
+ {
+ "id": "2db0bb8c-9d83-4e62-86ef-b3d999960d72",
+ "os": "Windows 2016 Standard",
+ "ram": 2048,
+ "disk": 50,
+ "main_ip": "100.68.102.43",
+ "vcpu_count": 1,
+ "region": "fra",
+ "plan": "vhp-1c-2gb-amd",
+ "date_created": "2022-12-05T12:50:30+00:00",
+ "status": "active",
+ "allowed_bandwidth": 3000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "45.77.142.1",
+ "power_status": "running",
+ "server_status": "installingbooting",
+ "v6_network": "",
+ "v6_main_ip": "",
+ "v6_network_size": 0,
+ "label": "windows-guest",
+ "internal_ip": "",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "windows-guest",
+ "tag": "",
+ "tags": [
+ "os:windows2016"
+ ],
+ "os_id": 240,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": []
+ },
+ {
+ "id": "e0aabdd7-7d68-448a-a0ce-a7712b09fcc1",
+ "os": "Arch Linux x64",
+ "ram": 6144,
+ "disk": 70,
+ "main_ip": "100.68.102.44",
+ "vcpu_count": 1,
+ "region": "sjc",
+ "plan": "vcg-a100-1c-6g-4vram",
+ "date_created": "2022-12-05T12:52:06+00:00",
+ "status": "active",
+ "allowed_bandwidth": 1000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "140.82.50.1",
+ "power_status": "running",
+ "server_status": "installingbooting",
+ "v6_network": "2001:19f0:face:1df3::",
+ "v6_main_ip": "2001:19f0:face:1df3:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "mldev-guest",
+ "internal_ip": "",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "mldev-guest",
+ "tag": "",
+ "tags": [],
+ "os_id": 535,
+ "app_id": 0,
+ "image_id": "mldev",
+ "firewall_group_id": "",
+ "features": [
+ "auto_backups",
+ "ipv6"
+ ]
+ },
+ {
+ "id": "90676f7b-5a34-49a8-b770-b0abed017577",
+ "os": "Application",
+ "ram": 2048,
+ "disk": 64,
+ "main_ip": "100.68.102.45",
+ "vcpu_count": 1,
+ "region": "ord",
+ "plan": "vhf-1c-2gb",
+ "date_created": "2022-12-05T12:54:37+00:00",
+ "status": "active",
+ "allowed_bandwidth": 2000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "149.28.114.1",
+ "power_status": "running",
+ "server_status": "installingbooting",
+ "v6_network": "2001:19f0:face:16ec::",
+ "v6_main_ip": "2001:19f0:face:16ec:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "wordpress-guest",
+ "internal_ip": "10.2.96.3",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "wordpress-guest",
+ "tag": "",
+ "tags": [
+ "vpc",
+ "vpc:d0db548b-5d50-4c94-9cdb-b083d46925f8",
+ "application"
+ ],
+ "os_id": 186,
+ "app_id": 2,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": [
+ "auto_backups",
+ "ipv6"
+ ]
+ }
+]
diff --git a/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory_page1.json b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory_page1.json
new file mode 100644
index 000000000..a4862285d
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory_page1.json
@@ -0,0 +1,179 @@
+{
+ "instances": [
+ {
+ "id": "f1c4ae0c-ea06-4449-a028-ffe6b05f9f80",
+ "os": "Custom Installed",
+ "ram": 512,
+ "disk": 10,
+ "main_ip": "100.68.102.38",
+ "vcpu_count": 1,
+ "region": "ewr",
+ "plan": "vc2-1c-0.5gb-v6",
+ "date_created": "2022-12-05T13:15:58+00:00",
+ "status": "active",
+ "allowed_bandwidth": 500,
+ "netmask_v4": "255.255.192.0",
+ "gateway_v4": "100.68.64.1",
+ "power_status": "running",
+ "server_status": "locked",
+ "v6_network": "2001:19f0:face:395c::",
+ "v6_main_ip": "2001:19f0:face:395c:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "",
+ "internal_ip": "10.1.96.3",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "",
+ "tag": "",
+ "tags": [],
+ "os_id": 159,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": [
+ "auto_backups",
+ "ipv6",
+ "ddos_protection"
+ ]
+ },
+ {
+ "id": "4adbf858-8426-40c4-8f48-91d83024bb5e",
+ "os": "Custom Installed",
+ "ram": 1024,
+ "disk": 25,
+ "main_ip": "100.68.102.39",
+ "vcpu_count": 1,
+ "region": "sea",
+ "plan": "vc2-1c-1gb",
+ "date_created": "2022-12-05T13:21:57+00:00",
+ "status": "active",
+ "allowed_bandwidth": 1000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "104.207.156.1",
+ "power_status": "stopped",
+ "server_status": "locked",
+ "v6_network": "2001:19f0:face:f17::",
+ "v6_main_ip": "2001:19f0:face:0f17:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "restore-guest",
+ "internal_ip": "",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "restore-guest",
+ "tag": "",
+ "tags": [],
+ "os_id": 159,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": [
+ "ipv6"
+ ]
+ },
+ {
+ "id": "5d8813ec-df65-4a69-8bfc-864aabe2a7d2",
+ "os": "Custom Installed",
+ "ram": 1024,
+ "disk": 25,
+ "main_ip": "100.68.102.40",
+ "vcpu_count": 1,
+ "region": "ord",
+ "plan": "vhp-1c-1gb-intel",
+ "date_created": "2022-12-05T13:29:19+00:00",
+ "status": "pending",
+ "allowed_bandwidth": 2000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "45.76.228.1",
+ "power_status": "running",
+ "server_status": "none",
+ "v6_network": "",
+ "v6_main_ip": "",
+ "v6_network_size": 0,
+ "label": "snapshot-guest",
+ "internal_ip": "",
+ "kvm": "",
+ "hostname": "snapshot-guest",
+ "tag": "",
+ "tags": [],
+ "os_id": 159,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": []
+ },
+ {
+ "id": "30c17c34-223f-436e-acbe-393af5293adb",
+ "os": "Debian 11 x64 (bullseye)",
+ "ram": 512,
+ "disk": 10,
+ "main_ip": "100.68.102.41",
+ "vcpu_count": 1,
+ "region": "ewr",
+ "plan": "vc2-1c-0.5gb-v6",
+ "date_created": "2022-12-05T12:43:00+00:00",
+ "status": "active",
+ "allowed_bandwidth": 500,
+ "netmask_v4": "255.255.192.0",
+ "gateway_v4": "100.68.64.1",
+ "power_status": "running",
+ "server_status": "ok",
+ "v6_network": "2001:19f0:face:8fd::",
+ "v6_main_ip": "2001:19f0:face:08fd:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "debian-guest",
+ "internal_ip": "10.1.96.3",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "debian-guest",
+ "tag": "",
+ "tags": [
+ "vpc",
+ "vpc:d0db548b-5d50-4c94-9cdb-b083d46925f8",
+ "os:debian"
+ ],
+ "os_id": 477,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": [
+ "auto_backups",
+ "ipv6"
+ ]
+ },
+ {
+ "id": "37d67f9f-17f0-4c56-879b-507355dc5174",
+ "os": "OpenBSD 7.2 x64",
+ "ram": 4096,
+ "disk": 30,
+ "main_ip": "100.68.102.42",
+ "vcpu_count": 1,
+ "region": "ewr",
+ "plan": "voc-g-1c-4gb-30s-amd",
+ "date_created": "2022-12-05T12:44:17+00:00",
+ "status": "active",
+ "allowed_bandwidth": 4000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "45.63.22.1",
+ "power_status": "running",
+ "server_status": "ok",
+ "v6_network": "",
+ "v6_main_ip": "",
+ "v6_network_size": 0,
+ "label": "openbsd-guest",
+ "internal_ip": "",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "openbsd-guest",
+ "tag": "",
+ "tags": [],
+ "os_id": 1968,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": []
+ }
+ ],
+ "meta": {
+ "total": 8,
+ "links": {
+ "next": "page2",
+ "prev": ""
+ }
+ }
+}
diff --git a/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory_page2.json b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory_page2.json
new file mode 100644
index 000000000..2f4ace8fa
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/fixtures/vultr_inventory_page2.json
@@ -0,0 +1,116 @@
+{
+ "instances": [
+ {
+ "id": "2db0bb8c-9d83-4e62-86ef-b3d999960d72",
+ "os": "Windows 2016 Standard",
+ "ram": 2048,
+ "disk": 50,
+ "main_ip": "100.68.102.43",
+ "vcpu_count": 1,
+ "region": "fra",
+ "plan": "vhp-1c-2gb-amd",
+ "date_created": "2022-12-05T12:50:30+00:00",
+ "status": "active",
+ "allowed_bandwidth": 3000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "45.77.142.1",
+ "power_status": "running",
+ "server_status": "installingbooting",
+ "v6_network": "",
+ "v6_main_ip": "",
+ "v6_network_size": 0,
+ "label": "windows-guest",
+ "internal_ip": "",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "windows-guest",
+ "tag": "",
+ "tags": [
+ "os:windows2016"
+ ],
+ "os_id": 240,
+ "app_id": 0,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": []
+ },
+ {
+ "id": "e0aabdd7-7d68-448a-a0ce-a7712b09fcc1",
+ "os": "Arch Linux x64",
+ "ram": 6144,
+ "disk": 70,
+ "main_ip": "100.68.102.44",
+ "vcpu_count": 1,
+ "region": "sjc",
+ "plan": "vcg-a100-1c-6g-4vram",
+ "date_created": "2022-12-05T12:52:06+00:00",
+ "status": "active",
+ "allowed_bandwidth": 1000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "140.82.50.1",
+ "power_status": "running",
+ "server_status": "installingbooting",
+ "v6_network": "2001:19f0:face:1df3::",
+ "v6_main_ip": "2001:19f0:face:1df3:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "mldev-guest",
+ "internal_ip": "",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "mldev-guest",
+ "tag": "",
+ "tags": [],
+ "os_id": 535,
+ "app_id": 0,
+ "image_id": "mldev",
+ "firewall_group_id": "",
+ "features": [
+ "auto_backups",
+ "ipv6"
+ ]
+ },
+ {
+ "id": "90676f7b-5a34-49a8-b770-b0abed017577",
+ "os": "Application",
+ "ram": 2048,
+ "disk": 64,
+ "main_ip": "100.68.102.45",
+ "vcpu_count": 1,
+ "region": "ord",
+ "plan": "vhf-1c-2gb",
+ "date_created": "2022-12-05T12:54:37+00:00",
+ "status": "active",
+ "allowed_bandwidth": 2000,
+ "netmask_v4": "255.255.254.0",
+ "gateway_v4": "149.28.114.1",
+ "power_status": "running",
+ "server_status": "installingbooting",
+ "v6_network": "2001:19f0:face:16ec::",
+ "v6_main_ip": "2001:19f0:face:16ec:5400:04ff:beef:cafe",
+ "v6_network_size": 64,
+ "label": "wordpress-guest",
+ "internal_ip": "10.2.96.3",
+ "kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=random-data",
+ "hostname": "wordpress-guest",
+ "tag": "",
+ "tags": [
+ "vpc",
+ "vpc:d0db548b-5d50-4c94-9cdb-b083d46925f8",
+ "application"
+ ],
+ "os_id": 186,
+ "app_id": 2,
+ "image_id": "",
+ "firewall_group_id": "",
+ "features": [
+ "auto_backups",
+ "ipv6"
+ ]
+ }
+ ],
+ "meta": {
+ "total": 8,
+ "links": {
+ "next": "",
+ "prev": "page1"
+ }
+ }
+}
diff --git a/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/test_vultr.py b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/test_vultr.py
new file mode 100644
index 000000000..aa8d8fbce
--- /dev/null
+++ b/ansible_collections/vultr/cloud/tests/unit/plugins/inventory/test_vultr.py
@@ -0,0 +1,233 @@
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import json
+import os.path
+import pytest
+
+from ansible.errors import AnsibleError, AnsibleParserError
+from ansible.inventory.data import InventoryData
+from ansible.parsing.dataloader import DataLoader
+from ansible.template import Templar
+
+import ansible_collections.vultr.cloud.plugins.inventory.vultr as module_under_test
+from ansible_collections.vultr.cloud.plugins.inventory.vultr import InventoryModule
+
+
+default_options = {
+ "api_endpoint": "https://test.api.vultr.com/v2",
+ "api_key": "TEST_VULTR_API_KEY",
+ "api_results_per_page": 100,
+ "api_timeout": 60,
+ "attributes": ["id", "region", "label", "plan", "hostname", "main_ip"],
+ "filters": [],
+ "plugin": "vultr.cloud.vultr",
+ "variable_prefix": "vultr_",
+ "validate_certs": True,
+}
+
+
+def get_option(opts):
+ def func(option):
+ return opts.get(option, False)
+
+ return func
+
+
+def load_fixture(filename):
+ return open(os.path.join(os.path.dirname(__file__), "fixtures", filename))
+
+
+def get_paginated_json_response(url):
+ cursor = "page1"
+ if "&cursor=" in url:
+ cursor = "page2"
+ return load_fixture("vultr_inventory_{0}.json".format(cursor))
+
+
+@pytest.fixture()
+def inventory():
+ r = InventoryModule()
+ r.inventory = InventoryData()
+ r.templar = Templar(loader=DataLoader())
+ return r
+
+
+@pytest.fixture()
+def instances():
+ return json.load(load_fixture("vultr_inventory.json"))
+
+
+def test_verify_file_no_filename(inventory):
+ assert inventory.verify_file("") is False
+
+
+def test_verify_file_valid_filename(tmp_path, inventory):
+ valid_config = tmp_path / "vultr.yaml"
+ valid_config.touch()
+ assert inventory.verify_file(str(valid_config)) is True
+
+
+def test_verify_file_invalid_filename(tmp_path, inventory):
+ invalid_config = tmp_path / "vultr.notyaml"
+ invalid_config.touch()
+ assert inventory.verify_file(str(invalid_config)) is False
+
+
+@pytest.mark.parametrize("cache_option", [True, False])
+def test_parse(tmp_path, inventory, mocker, cache_option):
+ inventory_file = tmp_path / "vultr.yaml"
+ inventory_file.write_text("---\nplugin: vultr.cloud.vultr")
+
+ plugin_cache_dir = tmp_path / "cache"
+
+ opts = default_options.copy()
+ opts.update(
+ {
+ "cache": cache_option,
+ "cache_connection": plugin_cache_dir,
+ "cache_plugin": "jsonfile",
+ }
+ )
+ inventory.get_option = mocker.MagicMock(side_effect=get_option(opts))
+
+ mocker.patch("{0}.Request".format(module_under_test.__name__))
+ RequestMock = module_under_test.Request
+
+ req = RequestMock.return_value
+ req.get.side_effect = get_paginated_json_response
+
+ inventory._redirected_names = ["vultr.cloud.vultr", "vultr"]
+ inventory._load_name = "vultr.cloud.vultr"
+ inventory.parse(inventory.inventory, DataLoader(), str(inventory_file))
+
+ if cache_option:
+ RequestMock.reset_mock()
+
+ inventory.parse(inventory.inventory, DataLoader(), str(inventory_file))
+ RequestMock.assert_not_called()
+
+ assert len(inventory.inventory.hosts.items()) > 0
+
+
+def test_parse_non_plugin_invalid_parameter(inventory):
+ try:
+ inventory.parse(None, DataLoader(), "")
+ assert False, "Expected parse() to raise AnsibleParserError"
+ except AnsibleParserError:
+ pass
+
+
+def test_get_instances(inventory, mocker):
+ inventory.get_option = mocker.MagicMock(side_effect=get_option(default_options))
+
+ mocker.patch("{0}.Request".format(module_under_test.__name__))
+ RequestMock = module_under_test.Request
+
+ req = RequestMock.return_value
+ req.get.side_effect = get_paginated_json_response
+
+ instance_list = inventory._get_instances()
+ assert len(instance_list) == 8
+
+
+def test_get_instances_invalid_api_key(inventory, mocker):
+ inventory.get_option = mocker.MagicMock(side_effect=get_option(default_options))
+
+ mocker.patch("{0}.Request".format(module_under_test.__name__))
+ RequestMock = module_under_test.Request
+
+ req = RequestMock.return_value
+ req.get.return_value = load_fixture("unauthorized_vultr_inventory.json")
+
+ try:
+ inventory._get_instances()
+ assert False, "Expected _get_instances() to raise AnsibleParserError"
+ except AnsibleParserError:
+ pass
+
+
+def test_get_instances_templated_api_key(inventory, mocker):
+ opts = default_options.copy()
+ opts.update({"api_key": '{{ lookup("random_choice", "TEST_VULTR_API_KEY") }}'})
+
+ inventory.get_option = mocker.MagicMock(side_effect=get_option(opts))
+
+ mocker.patch("{0}.Request".format(module_under_test.__name__))
+ RequestMock = module_under_test.Request
+
+ req = RequestMock.return_value
+ req.get.return_value = load_fixture("empty_vultr_inventory.json")
+
+ inventory._get_instances()
+
+ req_headers = RequestMock.call_args.kwargs["headers"]
+ assert req_headers.get("Authorization") == "Bearer TEST_VULTR_API_KEY"
+
+
+def test_populate(inventory, instances, mocker):
+ inventory.get_option = mocker.MagicMock(side_effect=get_option(default_options))
+ inventory._populate(instances)
+
+ assert len(inventory.inventory.hosts.items()) > 0
+
+
+def test_populate_with_empty_response(inventory, mocker):
+ inventory.get_option = mocker.MagicMock(side_effect=get_option(default_options))
+
+ mocker.patch("{0}.Request".format(module_under_test.__name__))
+ RequestMock = module_under_test.Request
+
+ req = RequestMock.return_value
+ req.get.return_value = load_fixture("empty_vultr_inventory.json")
+
+ inventory._populate(inventory._get_instances())
+
+ assert len(inventory.inventory.hosts.items()) == 0
+
+
+def test_populate_host_variables(inventory, instances, mocker):
+ inventory.get_option = mocker.MagicMock(side_effect=get_option(default_options))
+ inventory._populate(instances)
+
+ windows_host = inventory.inventory.get_host("windows-guest")
+ assert windows_host.vars["vultr_plan"] == "vhp-1c-2gb-amd"
+ assert windows_host.vars["vultr_region"] == "fra"
+ assert windows_host.vars["vultr_id"] == "2db0bb8c-9d83-4e62-86ef-b3d999960d72"
+
+
+def test_populate_host_variables_with_filters(inventory, instances, mocker):
+ opts = default_options.copy()
+ opts.update({"filters": ['vultr_id == "37d67f9f-17f0-4c56-879b-507355dc5174"']})
+
+ inventory.get_option = mocker.MagicMock(side_effect=get_option(opts))
+ inventory._populate(instances)
+
+ unfiltered_host = inventory.inventory.get_host("openbsd-guest")
+ filtered_host = inventory.inventory.get_host("debian-guest")
+
+ for host in inventory.inventory.hosts:
+ this_host = inventory.inventory.get_host(host)
+ assert "vultr_id" in this_host.vars
+ assert this_host.vars["vultr_id"] == "37d67f9f-17f0-4c56-879b-507355dc5174"
+
+ assert len(inventory.inventory.hosts.items()) == 1
+ assert unfiltered_host.vars["vultr_plan"] == "voc-g-1c-4gb-30s-amd"
+ assert filtered_host is None
+
+
+def test_passes_filters_invalid_filter_not_strict(inventory):
+ try:
+ inventory._passes_filters(["invalid filter"], {}, "host", False)
+ assert True
+ except AnsibleError:
+ assert False, "unexpected AnsibleError from _passes_filters()"
+
+
+def test_passes_filters_invalid_filter_strict(inventory):
+ try:
+ inventory._passes_filters(["invalid filter"], {}, "host", True)
+ assert False, "expected _passes_filters() to raise AnsibleError"
+ except AnsibleError:
+ pass