summaryrefslogtreecommitdiffstats
path: root/collections-debian-merged/ansible_collections/ngine_io/cloudstack
diff options
context:
space:
mode:
Diffstat (limited to 'collections-debian-merged/ansible_collections/ngine_io/cloudstack')
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/integration.yml80
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/publish.yml30
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/sanity.yml35
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/CHANGELOG.rst49
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/CONTRIBUTING.md6
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/COPYING621
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/FILES.json3155
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/MANIFEST.json41
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/README.md80
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/.gitignore1
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/changelog.yaml47
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/config.yaml29
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/fragments/.keep0
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/codecov.yml15
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/meta/runtime.yml68
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/cloudstack.py78
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/inventory/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/module_utils/cloudstack.py685
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_account.py450
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_affinitygroup.py230
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_cluster.py375
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_configuration.py270
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_disk_offering.py375
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_domain.py244
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_facts.py231
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_firewall.py439
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_host.py607
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_image_store.py246
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance.py1101
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_info.py370
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic.py285
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic_secondaryip.py267
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_password_reset.py151
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instancegroup.py181
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_ip_address.py279
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_iso.py436
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule.py371
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule_member.py345
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network.py633
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl.py197
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl_rule.py457
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_offering.py422
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_physical_network.py473
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_pod.py289
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_portforward.py398
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_project.py271
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_region.py187
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_resourcelimit.py202
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role.py205
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role_permission.py345
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_router.py368
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup.py193
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup_rule.py379
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_service_offering.py574
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_snapshot_policy.py349
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_sshkeypair.py261
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_staticnat.py249
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_storage_pool.py489
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_template.py741
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_traffic_type.py321
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_user.py436
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vlan_ip_range.py397
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vmsnapshot.py278
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_volume.py561
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc.py391
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc_offering.py319
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_connection.py349
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_customer_gateway.py343
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_gateway.py204
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone.py377
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone_info.py207
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/requirements.txt1
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.ini5
-rwxr-xr-xcollections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.py277
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/tasks/main.yml416
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/tasks/main.yml93
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/tasks/main.yml317
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/aliases1
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/defaults/main.yml6
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/tasks/main.yml23
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/defaults/main.yml5
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/account.yml76
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/cluster.yml76
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/main.yml204
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/storage.yml76
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/zone.yml59
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/tasks/main.yml143
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/tasks/main.yml241
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/defaults/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/tasks/main.yml447
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/tasks/main.yml438
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/tasks/main.yml166
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/defaults/main.yml5
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent.yml124
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent_display_name.yml47
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/cleanup.yml36
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/host.yml143
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/main.yml19
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present.yml342
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present_display_name.yml190
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/project.yml589
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/setup.yml27
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/sshkeys.yml181
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/tags.yml140
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/defaults/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/tasks/main.yml80
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/tasks/main.yml306
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/tasks/main.yml221
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/tasks/main.yml94
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/tasks/main.yml79
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/main.yml19
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/network.yml240
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/vpc.yml121
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/tasks/main.yml143
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/vars/main2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/tasks/main.yml392
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/vpc_network_tier.yml299
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/tasks/main.yml120
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/tasks/main.yml548
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/tasks/main.yml434
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/tasks/main.yml232
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/tasks/main.yml301
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/defaults/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/tasks/main.yml255
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/tasks/main.yml149
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/tasks/main.yml154
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/cpu.yml122
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/instance.yml108
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/main.yml104
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/tasks/main.yml130
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/tasks/main.yml303
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/tasks/main.yml183
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/tasks/main.yml79
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/absent.yml171
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/cleanup.yml7
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/main.yml4
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/present.yml163
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/setup.yml56
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/guest_vm_service_offering.yml223
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/system_vm_service_offering.yml151
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/tasks/main.yml176
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/tasks/main.yml197
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/tasks/main.yml465
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/defaults/main.yml5
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test1.yml160
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test2.yml181
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/tasks/main.yml174
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/tasks/main.yml618
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/tasks/main.yml461
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/defaults/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/tasks/main.yml165
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/defaults/main.yml8
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/common.yml322
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/extract_upload.yml190
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/tasks/main.yml728
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/tasks/main.yml427
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/tasks/main.yml205
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/tasks/main.yml208
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/tasks/main.yml108
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/aliases2
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/tasks/main.yml205
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/aliases3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/meta/main.yml3
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/tasks/main.yml73
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.10.txt0
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.9.txt0
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/requirements.txt4
-rw-r--r--collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/unit/modules/test_cs_traffic_type.py135
271 files changed, 40534 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/integration.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/integration.yml
new file mode 100644
index 00000000..1ddc5e29
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/integration.yml
@@ -0,0 +1,80 @@
+name: Collection integration
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ schedule:
+ - cron: 30 6 * * *
+
+jobs:
+ integration-test:
+ name: Integration v${{ matrix.container-version }} Ansible-${{ matrix.ansible-branch }} group${{ matrix.group }} Py${{ matrix.python-version }}
+ defaults:
+ run:
+ working-directory: ansible_collections/ngine_io/cloudstack
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version:
+ - 3.6
+ - 2.7
+ group:
+ - 1
+ - 2
+ ansible-branch:
+ - devel
+ container-version:
+ - 1.4.0
+ - 1.2.0
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v2
+ with:
+ path: ansible_collections/ngine_io/cloudstack
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install ansible and collection dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible-branch }}.tar.gz
+ pip install -r requirements.txt
+
+ - name: Build and install collection
+ run: |
+ ansible-galaxy collection build .
+ ansible-galaxy collection install *.gz
+
+ - name: Run the tests
+ run: >-
+ ansible-test
+ integration
+ --docker
+ -v
+ --diff
+ --color
+ --retry-on-error
+ --python ${{ matrix.python-version }}
+ --continue-on-error
+ --coverage
+ shippable/cs/group${{ matrix.group }}/
+ env:
+ ANSIBLE_CLOUDSTACK_CONTAINER: quay.io/ansible/cloudstack-test-container:${{ matrix.container-version }}
+
+ - name: Generate coverage report.
+ run: >-
+ ansible-test
+ coverage xml
+ -v
+ --requirements
+ --group-by command
+ --group-by version
+ - uses: codecov/codecov-action@v1
+ with:
+ fail_ci_if_error: false
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/publish.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/publish.yml
new file mode 100644
index 00000000..7d7df0f7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/publish.yml
@@ -0,0 +1,30 @@
+name: Upload release to Galaxy
+
+on:
+ release:
+ types: [created]
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: ansible_collections/ngine_io/cloudstack
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ path: ansible_collections/ngine_io/cloudstack
+ - name: Set up Python
+ uses: actions/setup-python@v1
+ 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/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/sanity.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/sanity.yml
new file mode 100644
index 00000000..3329a194
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/sanity.yml
@@ -0,0 +1,35 @@
+name: Sanity
+on:
+ schedule:
+ - cron: "* 12 * * *"
+ pull_request:
+
+jobs:
+ sanity:
+ name: Sanity (${{ matrix.ansible }})
+ defaults:
+ run:
+ working-directory: ansible_collections/ngine_io/cloudstack
+ strategy:
+ matrix:
+ ansible:
+ - stable-2.10
+ - stable-2.9
+ - devel
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v2
+ with:
+ path: ansible_collections/ngine_io/cloudstack
+
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: '3.x'
+
+ - 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/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CHANGELOG.rst b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CHANGELOG.rst
new file mode 100644
index 00000000..fd6f1c08
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CHANGELOG.rst
@@ -0,0 +1,49 @@
+==========================================
+Apache CloudStack Collection Release Notes
+==========================================
+
+.. contents:: Topics
+
+
+v1.2.0
+======
+
+Minor Changes
+-------------
+
+- cs_instance - Fixed an edge case caused by `displaytext` not available (https://github.com/ngine-io/ansible-collection-cloudstack/pull/49).
+- cs_network - Fixed constraints when creating networks. The param `gateway` is no longer required if the param `netmask` is given (https://github.com/ngine-io/ansible-collection-cloudstack/pull/54).
+
+v1.1.0
+======
+
+Minor Changes
+-------------
+
+- Deprecated the funtionality of first returned zone to be the default zone because of an unreliable API. Zone will be required beginning with next major version 2.0.0.
+- cs_ip_address - allow to pick a particular IP address for a network, available since CloudStack v4.13 (https://github.com/ngine-io/ansible-collection-cloudstack/issues/30).
+
+v1.0.1
+======
+
+Minor Changes
+-------------
+
+- cs_configuration - Workaround for empty global settings idempotency (https://github.com/ngine-io/ansible-collection-cloudstack/pull/25).
+
+v1.0.0
+======
+
+Minor Changes
+-------------
+
+- cs_vlan_ip_range - Added support to set IP range for system VMs (https://github.com/ngine-io/ansible-collection-cloudstack/pull/18)
+- cs_vlan_ip_range - Added support to specify pod name (https://github.com/ngine-io/ansible-collection-cloudstack/pull/20)
+
+v0.3.0
+======
+
+Minor Changes
+-------------
+
+- Added support for SSL CA cert verification (https://github.com/ngine-io/ansible-collection-cloudstack/pull/3)
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CONTRIBUTING.md b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CONTRIBUTING.md
new file mode 100644
index 00000000..44683c13
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/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/collections-debian-merged/ansible_collections/ngine_io/cloudstack/COPYING b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/COPYING
new file mode 100644
index 00000000..94a04532
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/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/collections-debian-merged/ansible_collections/ngine_io/cloudstack/FILES.json b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/FILES.json
new file mode 100644
index 00000000..53e7f294
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/FILES.json
@@ -0,0 +1,3155 @@
+{
+ "files": [
+ {
+ "name": ".",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".github",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "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": "901ae9494070cfaf2888a55873e289c5c491af91044a86cc99e647b92f1d8b11",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/sanity.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1b573d0df42509a12dc498f0275e0d799b6876b25b7ff72702b6ea70d449abfd",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/publish.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4e3a3b338deb27ec8dbfce3a48ddfe9585063e1ebfd80135fd04180cb9e47fe3",
+ "format": 1
+ },
+ {
+ "name": "CONTRIBUTING.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d61725d614410e2ee0a900fb0f6b6d742ad8fb689ae27c4d6a3a7f89e82fc791",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a20a58050d96de9b31b7c34d59344a0e66ca78ccdf4a3362edaf7aeb587f7808",
+ "format": 1
+ },
+ {
+ "name": "codecov.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "afc8758de58128c25c317b7e0577948745e05ad8f5d9e2e6b398fe351f237c4d",
+ "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": "578cefb3377270135166cd40a2464cb2726f1cb331c830110ee05b200667560f",
+ "format": 1
+ },
+ {
+ "name": "scripts",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "scripts/inventory",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "scripts/inventory/cloudstack.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "478052455665ad0f9af2a25636d2635d800893fdcf44234a4c9bd7ae02eab3a8",
+ "format": 1
+ },
+ {
+ "name": "scripts/inventory/cloudstack.ini",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "68687bdf204b24ce911c14663b8e69acb388c328779449bda69cc0828e548e16",
+ "format": 1
+ },
+ {
+ "name": "tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/modules",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/modules/test_cs_traffic_type.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d2b4ed18f086f4f0a8579f32e3b3decabfbbe586d3a1af78ee5462314d46d2f7",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.9.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/requirements.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c8a4ac4bfdef88e75d6e748e35a42fb4915947dfa2b7dd788626fd829600e014",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.10.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "tests/integration",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vlan_ip_range",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vlan_ip_range/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vlan_ip_range/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2f76af19234a916542ea1bc51dcfc63f2ee5fba78562ae4fbc052be036812035",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vlan_ip_range/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vlan_ip_range/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vlan_ip_range/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_customer_gateway",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_customer_gateway/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_customer_gateway/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "78ffd37aa31959ad88ab02c30493979cb82904da3fd584ae36a851b9f7aae534",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_customer_gateway/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_customer_gateway/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_customer_gateway/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3cd6a215c3f8e43d39b6a2e04e3ff76f0bcbf3edfeafdd1554615b6a9b4f8ff1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0b725eee393b6b5fa1a51131498bdb40f94841a4430d9c38894146f8e764b679",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_disk_offering",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_disk_offering/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_disk_offering/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c3438cb3148e9d0988a7ea4375dfd89d2c2dab0d67257177f11c2ecff61698d9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_disk_offering/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_disk_offering/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_disk_offering/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_domain",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_domain/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_domain/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2e70d8fb8c7855c7247a697738e6a0971a87ee6d51cbe2ea3f9c05c6d777a698",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_domain/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_domain/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_domain/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instancegroup",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instancegroup/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instancegroup/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e2c8bb27e2b569449117fac8b22f1c46ab3bc46309b0b9a1dd1502c450f5b058",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instancegroup/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instancegroup/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instancegroup/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_loadbalancer_rule",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_loadbalancer_rule/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_loadbalancer_rule/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "88ac6be7215520f724b5a5c379c8a60d18da7a804dfcfbd7ebdfc6d29f54be4b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_loadbalancer_rule/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_loadbalancer_rule/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_loadbalancer_rule/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_portforward",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_portforward/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_portforward/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "344c52179d018ce4e7156048768afc9d7b8a96447b937e1cbe57e8903a78b839",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_portforward/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_portforward/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6c59ba59148b0d1320caa47f882209934ee727522070decdff4442b9969f9922",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_portforward/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_portforward/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_portforward/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "02998a58ac5e2d50a05ea38a9fe9147dabc50c66e6a704d313abd815f0c7a5ab",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc_offering",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc_offering/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc_offering/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2502c1a6bee1dfd83edf7607b8990cd96e252cb9fc09924e0b3ef63d68d065ff",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc_offering/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc_offering/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc_offering/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_resourcelimit",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_resourcelimit/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_resourcelimit/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f161ed7ac158aed2aae7466b5b4a76cfe9022e36c015eb1fef38cea4b980b627",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_resourcelimit/tasks/instance.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1d89acf95bdbab94aed21af8979b6e6a279b6230be7defd96d20c1fdab51eea5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_resourcelimit/tasks/cpu.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9eaa824708a27315ec1ba5c3b8ad94916857bb744743d66a4424bb95b4b66851",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_resourcelimit/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_resourcelimit/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_resourcelimit/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_account",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_account/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_account/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3b07f0a3e941192fa759956eefa6c37b91f386effa4cb9494dcb698d5db5184a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_account/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_account/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_account/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_ip_address",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_ip_address/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_ip_address/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9035d7e10eabaa16be3d35db67a0fe267f1db7eca09ed29f669913c4c7789fda",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_ip_address/tasks/vpc.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "155dba88a0af93a0060b710c523a9810bf75d8f2dc861e25d4f1dab858c1c86e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_ip_address/tasks/network.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "15d3f1a3307082ddedfb26d2512e1f8685d13cfa9656f018fca2bf0a04ca1510",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_ip_address/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_ip_address/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_ip_address/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4d3bc0dde667bd969a99c8bd162ca2f45f309b8e0cc88862f3e7719f57522324",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule/tasks/absent.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "33c9d5e8514301ea8a08b25615c62068f5b431c2eb74eebed63f98c49abf6b4c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule/tasks/cleanup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "033109b067b97d720aae0d7c05b52cb75d5cbd489e0a0071e259117ebe8f8917",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule/tasks/present.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "11c980afde092def9b1786574f57aafe6c8575edd4b6f3043439c24e7c1ff840",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule/tasks/setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6d66e31908ee8d1f26a41413faa748bede36b4978de7463627d259efeb631722",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup_rule/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic_secondaryip",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic_secondaryip/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic_secondaryip/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5761da50b470ecdac2717f281f58cf92772cc72f5ddc37cfa70c2b3cea4af0cb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic_secondaryip/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic_secondaryip/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_nic_secondaryip/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_storage_pool",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_storage_pool/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_storage_pool/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dad8be1dcf1a0aff3f6b298b7eff915c0686516288012389d6c2a0a0f8a51c7b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_storage_pool/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_storage_pool/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_storage_pool/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vmsnapshot",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vmsnapshot/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vmsnapshot/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3cd6a215c3f8e43d39b6a2e04e3ff76f0bcbf3edfeafdd1554615b6a9b4f8ff1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vmsnapshot/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vmsnapshot/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d16390e4bc6fa20a760046083a7618be45b6837d9089f0f578aa07c5b0520de2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vmsnapshot/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vmsnapshot/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vmsnapshot/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_pod",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_pod/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_pod/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c535689653a4fa17f81e799bfd08233c8e6c922aa39a0b6f11d059f36e3669f6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_pod/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_pod/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_pod/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f34435f3e10a5b795d59cb93cbe5be3f076e392ae95aa71633da6a197f161dc2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "901a810242c3925f1b4bddda46b2d88f67e519f4b6083bcf8fb2558606183051",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume/tasks/extract_upload.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "080aa10d4de85b9b1362bddaff92f98541c8938eaf029025badd07be5810b65b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume/tasks/common.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "efe358347a46c9fa323eafb0cb3d13dc00acf12ac91f27801fd72e13f0d749f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_volume/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "81c00882d5027750debd495ca52af872f0598e5b1ab8149fad9cf917fdb43a99",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4e431dd4b7e38c2015973f2c38df88fafdb8fabc0d6cd324896d6e5d55c6a7bd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/tasks/storage.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fdba85274478328bc23c3c27b2281758e7917dd6f20cb4dc4f299c2489452fd7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/tasks/cluster.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b7391db25eb343fc12282964e43a5901ff4f412cdf155636dc76074255efb92c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/tasks/zone.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7fde8940bfecb63f5f6a066462df151d00f04653fa505fdae6b92cb27af818f4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/tasks/account.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f6c463b2e203267b31c12d4434dc4fdb630ecaf1bb2d486e6d826eff1e49b7a1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_configuration/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "68a32931f33f79650f95a87b32b3433e4381338d5b1ca31f2ebc9b731bea933b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_host",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_host/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_host/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5ba905c63b22589086a7c6a30846142a6b952fe16594c91aaf5a8714d089847b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_host/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_host/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_host/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1df97d660547f55323b190118a233cc0e4aae5a634e9c691e8fee64dba46b933",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "93d9e466eda38393a5c61922128f6a08d660ae6ac7247f404db75337d966333d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_zone_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e59e06cbfaa08da5d22a5e8ceb6438830027bde749902aaa6610644556cc1ae1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "82fefd0a537a0944caa4c0cc27fa910f0f4be3af7721b3e153fe221dc861abd1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_securitygroup/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_gateway",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_gateway/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_gateway/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f60ff37c5d6bc0eb7a1775deb3d95769d50acb19147d0224026bfa3663f47940",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_gateway/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_gateway/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_gateway/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_image_store",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_image_store/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_image_store/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "37e3d450b66d55ebe6bd62e95227e7f577b574cd49c462d339d0fc40c436aa57",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_image_store/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_image_store/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_image_store/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_snapshot_policy",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_snapshot_policy/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_snapshot_policy/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d089bedcbdca8f8f9958db1f15641382f596cfc57fcab6953699d97c2f83988e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_snapshot_policy/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_snapshot_policy/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_snapshot_policy/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_iso",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_iso/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_iso/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b300f611e7e7135993a4723c687b1cafd7645ebe364a1b5e8346f2e56022a19d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_iso/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_iso/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_iso/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_iso/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_iso/vars/main",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ceaa440c1cbe8e00a79d7e38d80a8a5cbcac80433ef5635757beeed08ffdf7f5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_password_reset",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_password_reset/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_password_reset/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "436edb2efdcc5a081992d0373ef892a8f8365845bda44ca74858dc5b17a3168a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_password_reset/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_password_reset/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance_password_reset/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_connection",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_connection/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_connection/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "69c3dde280feba63615cc92b06915f92e3d97eead5249c92736815719427e3b0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_connection/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_connection/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpn_connection/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e9f171e3921423692918610c59f13b2e3f54c2257333b5c5b3372f4b31341477",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c04acf19293639e0d95ee7a7b96e21b98b2012d008f2b21c81a3acabf7da71ef",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template/tasks/test2.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5a46fd33b402c788ae3d984e3e8fa472f960769d4e899f74d082d4d16d18c539",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template/tasks/test1.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b49ca50601acc42f14c9344acacd5078b28dff511b9afac5a6fa8ff05e4a4cd2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_template/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_physical_network",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_physical_network/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_physical_network/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4bdf9f930a44fc7b940bec01380b8c0f4a6a8094aee598778af2dd4f45672bef",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_physical_network/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_physical_network/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_physical_network/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_traffic_type",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_traffic_type/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_traffic_type/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "555e1db2372cf69d3a8f52f92be3bfae504bb9d17733c3de1af27819555d3c6c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_traffic_type/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_traffic_type/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_traffic_type/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_cluster",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_cluster/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_cluster/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b221ca593f1d6cc4423409c2907520009ce5a0b9d76b959e30aaae1e953995b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_cluster/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_cluster/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_cluster/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl_rule",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl_rule/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl_rule/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "835daf7a42f92968a97750b8b57def374a4d095a1ea4bfbf248dfb1852930138",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl_rule/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl_rule/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl_rule/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_region",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_region/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_region/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2e814b9b39cde2e07fcf66c75ea960cec7285f8ba6f3eacda68e504ba4d9f0e7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_region/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_region/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_region/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b333f132afa4d635d3d65906788d29230338a0421004bd632bda0ab5b824a671",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e88e45b01f0fd3179502e864d02eb9565a5c8af81ca64be8ace5c9f6a91463c8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/sshkeys.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "27b7d8a289e9a8eae40c0cb7a910df2216db3ff331f4c1ef846b63f5a24d7a8a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/project.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "be774b436b890ef832c7828bff578bd11d71ca38dc20bb837b3ca27c3e568eb0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/absent_display_name.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9fa46c79ea412b09525494b95e37ae0f69af77554f669faeb708d1c4325f486e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/host.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2369176246b141fbe33eeb3d2a5831434d90d585588cb59640c5e76a8bc35052",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/absent.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "584ef507f41cd26f390a1577a4a4ec8222af585a8bc208cedcd8a67201da8b9c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/cleanup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "45b55ab87c0e6f0618a2b787749a16eea5505feaf7c63ddf36b677347fae40f8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/present.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "36d3f3f5716c6bcf992d9dc5ca89e73ad39d4d0caf0cc5066d374eeb56ea9c51",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/present_display_name.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8e750ce18fc78fc6a80816e8e8f8f782bbcfce5b063b850f8d0a3ba7f1df9814",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c101e2db52029f736527268279eef4989371bb17b37ee1ed22249d8cba50b7e6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/tasks/tags.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "55f84d21aec9825c83de1c89184d2d5e24ee09230d754ca7bffc9b07b668dff5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_instance/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_common",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_common/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_common/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "616327d556e1811bf053b650fd4d39f86c5725601251926a6adf9e97dd0ca2ac",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_common/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_common/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6d24a28d3e2f90db822b1a43239bdcae7366c592c0494fb53d66efc24f210dab",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_common/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e084a3683ef795d1cdbf5e9b253f2ca1f783ae0d0d6e47e419acbbc4fc80bbfa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d13fd3db2ddc6b26b21a32ee63bfc8b837ab918a2b3f134b451156fcd09a7844",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_vpc/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_firewall",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_firewall/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_firewall/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bce5685bb3f56dcfb18126f2dab2bcb20b0227ec5af2626a0ea99592d3837908",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_firewall/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_firewall/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d2924b0f2adf14b7dfd6c808cca36a5e11491e1c81954f8bd4814acc8de71224",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_firewall/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_firewall/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_firewall/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_user",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_user/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_user/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "723bfa451f6b5fa598677b451b81a93eca4dd7ec004e7bc5b1bff865389280f6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_user/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_user/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_user/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_sshkeypair",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_sshkeypair/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_sshkeypair/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7e5a4ec5322983b45afa12ae5e7ce6fe9cf98684d1ed3556e8947d84e3be61b0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_sshkeypair/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_sshkeypair/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_sshkeypair/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9cd1515f2e8a1e3e66f2d95d9112d7f9deddf7a6800d791dfd5b54264bb6f217",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_acl/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_offering",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_offering/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_offering/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "018b8d542e2352e52319c4fc33991f80899e82cea1b0bc6f34428fd73c553ded",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_offering/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_offering/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network_offering/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "440a776e871e1e719a5f6aaa2c0fcdd32a68991ad416c3c09e3a8beb7f207466",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network/tasks/vpc_network_tier.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7a62edd637b4c99aa83306cbba8e355ae565ec5e9bbceb6849493b6c3289d8ad",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_network/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role_permission",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role_permission/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role_permission/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5f680e43c73283119136e0210f40d3b7224393a0c27dee9feb34e095f9055b33",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role_permission/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role_permission/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_role_permission/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_project",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_project/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_project/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3826fd7a8983ae5350ba356789a8d6d3c196081326b1d47f7325d6e07b1fdb2c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_project/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_project/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_project/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_affinitygroup",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_affinitygroup/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_affinitygroup/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fee4f4a1d95c32a864529c3aa66e4a5842566759600498962c616d774c780560",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_affinitygroup/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_affinitygroup/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_affinitygroup/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_service_offering",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_service_offering/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_service_offering/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "162ccba75799e1764a780a3efabbd083b8999b04c6fb010b73cee5ff4c6b2400",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_service_offering/tasks/system_vm_service_offering.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "08e092f11a312f6509e172b83079f86ae4f623fb140c212129cd4bc168156f00",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_service_offering/tasks/guest_vm_service_offering.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5e3355d332a1366ac284c390396b41df25b5d05824d1f0ff3ff5d7b1cae96e1b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_service_offering/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_service_offering/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_service_offering/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_router",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_router/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_router/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7a04fd3a4077d4b7aa61897011b17349358e0a4e18cccb1df4e8c6ebcc3ac5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_router/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_router/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cs_router/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536",
+ "format": 1
+ },
+ {
+ "name": "plugins",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments/cloudstack.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1dc4d5b06785e750f58dea4908c7eadb72b2b8afb1e3a6c8827c030a62dc09e0",
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments/__init__.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "plugins/inventory",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/inventory/__init__.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/cloudstack.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f8550690f9781333d7d2dd0004d1ef2c7371c20bb740f271f73271cca7c32bc0",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_user.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f88272e1c57a99e1dfc3c7d15387be9ba1cee7dcb8c006a3a139a00c51d2f9cd",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_vmsnapshot.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b05403414eda51030bf22bb684b092e38f66362412a9c0bbbc98e804744acb3a",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_instance_nic.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bb6635c5bc7043e24cd4934c5b166d939ce6a7e52d81ac308fea4547dc159765",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_router.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "77e68182ff9763e80f186730eb7e4317732a5f18feda5f55f551427bf2b674e4",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_facts.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "90babadf599efc7386d2330e11c2dc0dc5942024314865beada155b706235f1f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_storage_pool.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "858db5a5c6bc8dd0068173287ed2f9f20b44458f26a29eceb19c88312335038f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_pod.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8208a91b94512910ccbbab450d56b0fcf27c031b65566fdbebaa1a42fcdf1a14",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_configuration.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f36ad5c05a8d90658fa764b26bf8d1f48f914636e04a0b43439ad383300b16fd",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_vpn_gateway.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4fea1f6802bcd3e072f25019d145392065dd8448077f89bf57727853a874b6df",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_vpn_connection.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "86cdc94e4c32a7f1e92a8699f8f7a30d0d6c08d71b5d9bd79753fc15fd03d8b1",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_vpn_customer_gateway.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "19a4b82df0d58b2d74e270e484ed700687cd6c017df41d2db20ceaa7f33d02e0",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_cluster.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bdadc9c314b4360254c6d1fbc2d99c2c49bbb279b8688b7ea1e7ecc0ae376b8b",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_traffic_type.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "26fa654a85cd1084c25b9342828f1e9465379853b2e2bd9a5f9b73a93f4baa7a",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_physical_network.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3cb9342b03424b394310b4bc6ce959bcde8abe5a1297daab0b2cf2594e282e50",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_domain.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e1792de992e67d1d35332be1c1a266bfb4844ad734e9306038fafb7f29e856a7",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_loadbalancer_rule_member.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b86ad01dd0f0c28e94566d11e0bb5f30602db95c114269cec4f32582ba11b46e",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_instance_nic_secondaryip.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "416e26b7a322f3639e46aa3baebf916437d5ab7a5267b16926d04f4902e27b5f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_snapshot_policy.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5464689f73fb50206aa91c04df89f50ae649fb86a1d577b59b53f32636899908",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_instance.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "39a33cd4487edd75005aec6e5c00657d48ba3e1e683f0efa0b3e23d1fdb04ac9",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_volume.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "41981cfd82c9afd850bb76fa6b178fa21bb58061d0e6a8db39c5c94362cdbd92",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_instance_password_reset.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "00b1bb39cb5134ca8beadc8dd3d651a1b7987b4f52d410bf6c720e643748fa07",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_loadbalancer_rule.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d255a1a2646f86197322c62d4aeb4b5a5f87f47815501f66f5220d793461e647",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_disk_offering.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e67dfad492025f3b1b94faf32dd02fc7a15ddfafbda8af1d23409b0e227a4f7d",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_firewall.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "600e65641433ad461384bda7a92c941c75f9e202df17a847f7a208dc7d6751b4",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_securitygroup_rule.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a8ad4f4fa55a24b3df7990d06cc90dd5aa7a01dcec3e06f8b81c6ed4f36b33da",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_instance_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "987b16953b28e483046a59ff1b79a1b0f07b31eab05713757ee2b3e931835f46",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_account.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "50f82f57ec698a243f290ee9e0c61db7aa04bc5dd9057e8b3651b477d019a33b",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_instancegroup.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "33828978e373f0a3fc9e212bdde35e990e02b46c6db9b0d74c2db9d29218f3ba",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_securitygroup.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8cfb4d57198cdf397e86331b0a30fec8cffd85d04ab1d66c46310fd7e15596c6",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_network.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7e682efa26cabca448fe874b79ae4fed44a896e8ac91f71e6951fccd5d858faf",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/__init__.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_project.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "083ac8aa569b719589c462eb79cceb8b02cccdf7665c2b1e60097195e3ae3466",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_zone.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4504a896257a783eec3634b54f560fe5ac5497556abb6716f5eec1a744b5ccb0",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_network_acl.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "95bdf3daeab85335f79033ec894a683583993ee344e3a6c2366271a7c86a7388",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_template.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "139ea6f288b7a9ab9b47c9687baa4ab5a702b340f6405f2fdfe81148a3026fb3",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_zone_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8f07b8091bcfca69c6aea9eabad4fd21db193502b13460e1653848637d58a8e2",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_network_acl_rule.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c31328ad56bf7c19b9fe497f51a96c886c4d56271d836fa1bd7b08003b026266",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_iso.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6b5b90fb2651a7e201841fb92788949f0a682dca715cb5c0daa84bfedae4e653",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_resourcelimit.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f5f011e307013938087cc17f9b12f53db18fe921386553bce32a17cff61f2e8e",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_region.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "40b8580c476de8e7e090e4d3531f777fe2284867c93265034099f927f2841601",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_role_permission.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3c43f7ab6a107f046a195ecf639a102ebf6f50091c3d3a007b30cdc735188d2d",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_vpc.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8737ac56bc12ca7283ce098f89384ba3d3a746b42310a80d53e497ef7cbfa816",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_vpc_offering.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f55428af6c509516322db6489f7f6c7d80e1a8cb14cfc2192f82d9b45b51bd31",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_role.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9ecac2c3bfb4f7343e4787a2335f0a9ae13b8dc4ee9f0c2bc590cbbb80760bbb",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_sshkeypair.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9050e14109a0f8fbc0c761a115bf727bfda3e1a0d254a838c543e2e1634a57b8",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_service_offering.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4f38f829a1ae6b297cdd4e58f8d2b6e3906c60752fc0fb24432627ace509ccbf",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_host.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "11d5cca2e6bf0f534d21dd268cb96cabe932be47cec148ed427a7783704c7b06",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_affinitygroup.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fc89dbe37b31267715eaf1037ccc92c787c93f7aaee4c0dfc42e9c9a8c397a86",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_ip_address.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ec0664301eef74063ec7eac629e848e0b092350a9affe067bcea182c4e1ab5b8",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_network_offering.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1880e7f84fa082439c7969c41c95faedf45300ee0283fb000968e9e881bd356f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_portforward.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a6b8333a131cdbb419d623f709712f3a2d52c6994fc6a8a5d30c3171a45782e6",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_staticnat.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2dbdf658a2bf86366669dbe012196fce657e125fc3fc3fc12bdce84911138966",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_image_store.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b6a0c66f180bc32b9994fe355c742c03400b946cb36aac0b121782da61845eb2",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/cs_vlan_ip_range.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cd724e08554b029c827a2d9e1e43d39c945484d41577a6673f5dff88c34b9579",
+ "format": 1
+ },
+ {
+ "name": "README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7903e82601897dc35af9245b374058d1fb712bcb3d1c4f7c53d2d6eb29a000e8",
+ "format": 1
+ },
+ {
+ "name": "changelogs",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "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": "ed86f4354405bab1f95e13c965959d170fdd4bbc5757dd0326f0c1237324930e",
+ "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": "bbbd9964907510188daf90dbf5618d86e0e0f359032711c367b0e20844148412",
+ "format": 1
+ },
+ {
+ "name": "requirements.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e5fe54d7f891bf3cdb4831fe2029e870514833d7813fcb55561a1103860f36db",
+ "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/collections-debian-merged/ansible_collections/ngine_io/cloudstack/MANIFEST.json b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/MANIFEST.json
new file mode 100644
index 00000000..3c2c4a0b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/MANIFEST.json
@@ -0,0 +1,41 @@
+{
+ "collection_info": {
+ "namespace": "ngine_io",
+ "name": "cloudstack",
+ "version": "1.2.0",
+ "authors": [
+ "Ren\u00e9 Moser <mail@renemoser.net>",
+ "David Passante (@dpassante)",
+ "Netservers Ltd. <support@netservers.co.uk>",
+ "Patryk D. Cichy <patryk.d.cichy@gmail.com>",
+ "Darren Worrall <darren@iweb.co.uk>",
+ "Marc-Aur\u00e8le Brothier (@marcaurele)",
+ "Jefferson Gir\u00e3o <jefferson@girao.net>",
+ "Gregor Riepl (@onitake)"
+ ],
+ "readme": "README.md",
+ "tags": [
+ "cloud",
+ "cloudstack",
+ "ngine_io"
+ ],
+ "description": "Ansible Collection for Apache CloudStack based clouds",
+ "license": [
+ "GPL-3.0-or-later"
+ ],
+ "license_file": null,
+ "dependencies": {},
+ "repository": "https://github.com/ngine-io/ansible-collection-cloudstack",
+ "documentation": "",
+ "homepage": "https://github.com/ngine-io/ansible-collection-cloudstack",
+ "issues": "https://github.com/ngine-io/ansible-collection-cloudstack/issues"
+ },
+ "file_manifest_file": {
+ "name": "FILES.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d3565502e4872c321d5cd6bc49a05a497f5fdea67c8542c50701c3ec02a10905",
+ "format": 1
+ },
+ "format": 1
+} \ No newline at end of file
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/README.md b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/README.md
new file mode 100644
index 00000000..4e5b3e59
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/README.md
@@ -0,0 +1,80 @@
+![Collection integration](https://github.com/ngine-io/ansible-collection-cloudstack/workflows/Collection%20integration/badge.svg)
+ [![Codecov](https://img.shields.io/codecov/c/github/ngine-io/ansible-collection-cloudstack)](https://codecov.io/gh/ngine-io/ansible-collection-cloudstack)
+[![License](https://img.shields.io/badge/license-GPL%20v3.0-brightgreen.svg)](LICENSE)
+
+# Ansible Collection for Apache CloudStack Clouds
+
+This collection provides a series of Ansible modules and plugins for interacting with the [Apache CloudStack](https://cloudstack.apache.org) Cloud.
+
+## Requirements
+
+- ansible version >= 2.9
+
+## Installation
+
+To install the collection hosted in Galaxy:
+
+```bash
+ansible-galaxy collection install ngine_io.cloudstack
+```
+
+To upgrade to the latest version of the collection:
+
+```bash
+ansible-galaxy collection install ngine_io.cloudstack --force
+```
+
+## Usage
+
+### Playbooks
+
+To use a module from Apache CloudStack collection, please reference the full namespace, collection name, and modules name that you want to use:
+
+```yaml
+---
+- name: Using Apache CloudStack collection
+ hosts: localhost
+ tasks:
+ - ngine_io.cloudstack.cs_instance:
+ ...
+```
+
+Or you can add full namepsace and collecton name in the `collections` element:
+
+```yaml
+---
+- name: Using Apache CloudStack collection
+ hosts: localhost
+ collections:
+ - ngine_io.cloudstack
+ tasks:
+ - cs_instance:
+ ...
+```
+
+### Roles
+
+For existing Ansible roles, please also reference the full namespace, collection name, and modules name which used in tasks instead of just modules name.
+
+### Plugins
+
+To use a plugin, please reference the full namespace, collection name, and plugin name that you want to use:
+
+```yaml
+plugin: ngine_io.cloudstack.cloudstack
+```
+
+## 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.
+
+## License
+
+GNU General Public License v3.0
+
+See [COPYING](COPYING) to see the full text.
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/.gitignore b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/.gitignore
new file mode 100644
index 00000000..6be6b533
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/.gitignore
@@ -0,0 +1 @@
+/.plugin-cache.yaml
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/changelog.yaml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/changelog.yaml
new file mode 100644
index 00000000..aa38f675
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/changelog.yaml
@@ -0,0 +1,47 @@
+ancestor: null
+releases:
+ 0.3.0:
+ changes:
+ minor_changes:
+ - Added support for SSL CA cert verification (https://github.com/ngine-io/ansible-collection-cloudstack/pull/3)
+ fragments:
+ - 3-ca-cert-verification.yml
+ release_date: '2020-07-04'
+ 1.0.0:
+ changes:
+ minor_changes:
+ - cs_vlan_ip_range - Added support to set IP range for system VMs (https://github.com/ngine-io/ansible-collection-cloudstack/pull/18)
+ - cs_vlan_ip_range - Added support to specify pod name (https://github.com/ngine-io/ansible-collection-cloudstack/pull/20)
+ fragments:
+ - 18-for_system_vms_cs_vlan_ip_range.yml
+ - 20-cs_vlan_ip_range_pod.yml
+ release_date: '2020-08-15'
+ 1.0.1:
+ changes:
+ minor_changes:
+ - cs_configuration - Workaround for empty global settings idempotency (https://github.com/ngine-io/ansible-collection-cloudstack/pull/25).
+ fragments:
+ - 25-empty_config_idempotency.yml
+ release_date: '2020-08-30'
+ 1.1.0:
+ changes:
+ minor_changes:
+ - Deprecated the funtionality of first returned zone to be the default zone
+ because of an unreliable API. Zone will be required beginning with next major
+ version 2.0.0.
+ - cs_ip_address - allow to pick a particular IP address for a network, available
+ since CloudStack v4.13 (https://github.com/ngine-io/ansible-collection-cloudstack/issues/30).
+ fragments:
+ - cs_ip_address_reservation.yaml
+ - default_zone_deprecation.yaml
+ release_date: '2020-11-26'
+ 1.2.0:
+ changes:
+ minor_changes:
+ - cs_instance - Fixed an edge case caused by `displaytext` not available (https://github.com/ngine-io/ansible-collection-cloudstack/pull/49).
+ - cs_network - Fixed constraints when creating networks. The param `gateway`
+ is no longer required if the param `netmask` is given (https://github.com/ngine-io/ansible-collection-cloudstack/pull/54).
+ fragments:
+ - 49-cs_instance-fix-keyerror.yml
+ - 54-cs_network-fix-constraints.yml
+ release_date: '2021-02-02'
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/config.yaml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/config.yaml
new file mode 100644
index 00000000..3cb90f28
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/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
+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: Apache CloudStack Collection
+trivial_section_name: trivial
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/fragments/.keep b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/fragments/.keep
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/fragments/.keep
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/codecov.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/codecov.yml
new file mode 100644
index 00000000..0815ba0e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/codecov.yml
@@ -0,0 +1,15 @@
+---
+coverage:
+ precision: 2
+ round: down
+ range: "70...100"
+ status:
+ project:
+ default:
+ informational: true
+ threshold: 10%
+ patch:
+ default:
+ threshold: 10%
+fixes:
+ - "/ansible_collections/ngine_io/cloudstack/::"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/meta/runtime.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/meta/runtime.yml
new file mode 100644
index 00000000..22f211d6
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/meta/runtime.yml
@@ -0,0 +1,68 @@
+requires_ansible: '>=2.9.10'
+action_groups:
+ cloudstack:
+ - cs_traffic_type
+ - cs_cluster
+ - cs_network_acl
+ - cs_affinitygroup
+ - cs_user
+ - cs_host
+ - cs_resourcelimit
+ - cs_zone_info
+ - cs_loadbalancer_rule
+ - cs_vpn_connection
+ - cs_iso
+ - cs_sshkeypair
+ - cs_instancegroup
+ - cs_securitygroup
+ - cs_vlan_ip_range
+ - cs_vpn_gateway
+ - cs_loadbalancer_rule_member
+ - cs_ip_address
+ - cs_pod
+ - cs_portforward
+ - cs_role_permission
+ - cs_vpc_offering
+ - cs_securitygroup_rule
+ - cs_vpc
+ - cs_instance_nic
+ - cs_region
+ - cs_firewall
+ - cs_role
+ - cs_router
+ - cs_template
+ - cs_disk_offering
+ - cs_vpn_customer_gateway
+ - cs_snapshot_policy
+ - cs_project
+ - cs_instance_password_reset
+ - cs_staticnat
+ - cs_storage_pool
+ - cs_zone
+ - cs_configuration
+ - cs_service_offering
+ - cs_vmsnapshot
+ - cs_network_offering
+ - cs_physical_network
+ - cs_instance_nic_secondaryip
+ - cs_network_acl_rule
+ - cs_image_store
+ - cs_domain
+ - cs_network
+ - cs_instance_info
+ - cs_account
+ - cs_instance
+ - cs_volume
+
+plugin_routing:
+ modules:
+ cs_instance_facts:
+ deprecation:
+ removal_date: 2021-12-12
+ warning_text: module was renamed to ngine_io.cloudstack.cs_instance_info
+ redirect: ngine_io.cloudstack.cs_instance_info
+ cs_zone_facts:
+ deprecation:
+ removal_date: 2021-12-12
+ warning_text: module was renamed to ngine_io.cloudstack.cs_zone_info
+ redirect: ngine_io.cloudstack.cs_zone_info
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/__init__.py
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/cloudstack.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/cloudstack.py
new file mode 100644
index 00000000..af13a3af
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/cloudstack.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015, 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):
+
+ # Standard cloudstack documentation fragment
+ DOCUMENTATION = r'''
+options:
+ api_key:
+ description:
+ - API key of the CloudStack API.
+ - If not given, the C(CLOUDSTACK_KEY) env variable is considered.
+ - As the last option, the value is taken from the ini config file, also see the notes.
+ type: str
+ api_secret:
+ description:
+ - Secret key of the CloudStack API.
+ - If not set, the C(CLOUDSTACK_SECRET) env variable is considered.
+ - As the last option, the value is taken from the ini config file, also see the notes.
+ type: str
+ api_url:
+ description:
+ - URL of the CloudStack API e.g. https://cloud.example.com/client/api.
+ - If not given, the C(CLOUDSTACK_ENDPOINT) env variable is considered.
+ - As the last option, the value is taken from the ini config file, also see the notes.
+ type: str
+ api_http_method:
+ description:
+ - HTTP method used to query the API endpoint.
+ - If not given, the C(CLOUDSTACK_METHOD) env variable is considered.
+ - As the last option, the value is taken from the ini config file, also see the notes.
+ - Fallback value is C(get) if not specified.
+ type: str
+ choices: [ get, post ]
+ api_timeout:
+ description:
+ - HTTP timeout in seconds.
+ - If not given, the C(CLOUDSTACK_TIMEOUT) env variable is considered.
+ - As the last option, the value is taken from the ini config file, also see the notes.
+ - Fallback value is 10 seconds if not specified.
+ type: int
+ api_region:
+ description:
+ - Name of the ini section in the C(cloustack.ini) file.
+ - If not given, the C(CLOUDSTACK_REGION) env variable is considered.
+ type: str
+ default: cloudstack
+ api_verify_ssl_cert:
+ description:
+ - CA authority cert file.
+ - If not given, the C(CLOUDSTACK_VERIFY) env variable is considered.
+ - As the last option, the value is taken from the ini config file, also see the notes.
+ - Fallback value is C(null) if not specified.
+ type: str
+requirements:
+ - python >= 2.6
+ - cs >= 0.9.0
+notes:
+ - Ansible uses the C(cs) library's configuration method if credentials are not
+ provided by the arguments C(api_url), C(api_key), C(api_secret).
+ Configuration is read from several locations, in the following order.
+ The C(CLOUDSTACK_ENDPOINT), C(CLOUDSTACK_KEY), C(CLOUDSTACK_SECRET) and
+ C(CLOUDSTACK_METHOD). C(CLOUDSTACK_TIMEOUT) environment variables.
+ A C(CLOUDSTACK_CONFIG) environment variable pointing to an C(.ini) file.
+ A C(cloudstack.ini) file in the current working directory.
+ A C(.cloudstack.ini) file in the users home directory.
+ Optionally multiple credentials and endpoints can be specified using ini sections in C(cloudstack.ini).
+ Use the argument C(api_region) to select the section name, default section is C(cloudstack).
+ See https://github.com/exoscale/cs for more information.
+ - A detailed guide about cloudstack modules can be found in the L(CloudStack Cloud Guide,../scenario_guides/guide_cloudstack.html).
+ - This module supports check mode.
+'''
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/inventory/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/inventory/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/inventory/__init__.py
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/module_utils/cloudstack.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/module_utils/cloudstack.py
new file mode 100644
index 00000000..ac310ecb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/module_utils/cloudstack.py
@@ -0,0 +1,685 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, 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 os
+import sys
+import time
+import traceback
+
+from ansible.module_utils._text import to_text, to_native
+from ansible.module_utils.basic import missing_required_lib
+
+CS_IMP_ERR = None
+try:
+ from cs import CloudStack, CloudStackException, read_config
+ HAS_LIB_CS = True
+except ImportError:
+ CS_IMP_ERR = traceback.format_exc()
+ HAS_LIB_CS = False
+
+
+if sys.version_info > (3,):
+ long = int
+
+
+def cs_argument_spec():
+ return dict(
+ api_key=dict(default=os.environ.get('CLOUDSTACK_KEY')),
+ api_secret=dict(default=os.environ.get('CLOUDSTACK_SECRET'), no_log=True),
+ api_url=dict(default=os.environ.get('CLOUDSTACK_ENDPOINT')),
+ api_http_method=dict(choices=['get', 'post'], default=os.environ.get('CLOUDSTACK_METHOD')),
+ api_timeout=dict(type='int', default=os.environ.get('CLOUDSTACK_TIMEOUT')),
+ api_region=dict(default=os.environ.get('CLOUDSTACK_REGION') or 'cloudstack'),
+ api_verify_ssl_cert=dict(default=os.environ.get('CLOUDSTACK_VERIFY')),
+ )
+
+
+def cs_required_together():
+ return [['api_key', 'api_secret']]
+
+
+class AnsibleCloudStack:
+
+ def __init__(self, module):
+ if not HAS_LIB_CS:
+ module.fail_json(msg=missing_required_lib('cs'), exception=CS_IMP_ERR)
+
+ self.result = {
+ 'changed': False,
+ 'diff': {
+ 'before': dict(),
+ 'after': dict()
+ }
+ }
+
+ # Common returns, will be merged with self.returns
+ # search_for_key: replace_with_key
+ self.common_returns = {
+ 'id': 'id',
+ 'name': 'name',
+ 'created': 'created',
+ 'zonename': 'zone',
+ 'state': 'state',
+ 'project': 'project',
+ 'account': 'account',
+ 'domain': 'domain',
+ 'displaytext': 'display_text',
+ 'displayname': 'display_name',
+ 'description': 'description',
+ }
+
+ # Init returns dict for use in subclasses
+ self.returns = {}
+ # these values will be casted to int
+ self.returns_to_int = {}
+ # these keys will be compared case sensitive in self.has_changed()
+ self.case_sensitive_keys = [
+ 'id',
+ 'displaytext',
+ 'displayname',
+ 'description',
+ ]
+
+ self.module = module
+ self._cs = None
+
+ # Helper for VPCs
+ self._vpc_networks_ids = None
+
+ self.domain = None
+ self.account = None
+ self.project = None
+ self.ip_address = None
+ self.network = None
+ self.physical_network = None
+ self.vpc = None
+ self.zone = None
+ self.vm = None
+ self.vm_default_nic = None
+ self.os_type = None
+ self.hypervisor = None
+ self.capabilities = None
+ self.network_acl = None
+
+ @property
+ def cs(self):
+ if self._cs is None:
+ api_config = self.get_api_config()
+ self._cs = CloudStack(**api_config)
+ return self._cs
+
+ def get_api_config(self):
+ api_region = self.module.params.get('api_region') or os.environ.get('CLOUDSTACK_REGION')
+ try:
+ config = read_config(api_region)
+ except KeyError:
+ config = {}
+
+ api_config = {
+ 'endpoint': self.module.params.get('api_url') or config.get('endpoint'),
+ 'key': self.module.params.get('api_key') or config.get('key'),
+ 'secret': self.module.params.get('api_secret') or config.get('secret'),
+ 'timeout': self.module.params.get('api_timeout') or config.get('timeout') or 10,
+ 'method': self.module.params.get('api_http_method') or config.get('method') or 'get',
+ 'verify': self.module.params.get('api_verify_ssl_cert') or config.get('verify'),
+ }
+ self.result.update({
+ 'api_region': api_region,
+ 'api_url': api_config['endpoint'],
+ 'api_key': api_config['key'],
+ 'api_timeout': int(api_config['timeout']),
+ 'api_http_method': api_config['method'],
+ 'api_verify_ssl_cert': api_config['verify'],
+ })
+ if not all([api_config['endpoint'], api_config['key'], api_config['secret']]):
+ self.fail_json(msg="Missing api credentials: can not authenticate")
+ return api_config
+
+ def fail_json(self, **kwargs):
+ self.result.update(kwargs)
+ self.module.fail_json(**self.result)
+
+ def get_or_fallback(self, key=None, fallback_key=None):
+ value = self.module.params.get(key)
+ if not value:
+ value = self.module.params.get(fallback_key)
+ return value
+
+ def has_changed(self, want_dict, current_dict, only_keys=None, skip_diff_for_keys=None):
+ result = False
+ for key, value in want_dict.items():
+
+ # Optionally limit by a list of keys
+ if only_keys and key not in only_keys:
+ continue
+
+ # Skip None values
+ if value is None:
+ continue
+
+ if key in current_dict:
+ if isinstance(value, (int, float, long, complex)):
+
+ # ensure we compare the same type
+ if isinstance(value, int):
+ current_dict[key] = int(current_dict[key])
+ elif isinstance(value, float):
+ current_dict[key] = float(current_dict[key])
+ elif isinstance(value, long):
+ current_dict[key] = long(current_dict[key])
+ elif isinstance(value, complex):
+ current_dict[key] = complex(current_dict[key])
+
+ if value != current_dict[key]:
+ if skip_diff_for_keys and key not in skip_diff_for_keys:
+ self.result['diff']['before'][key] = current_dict[key]
+ self.result['diff']['after'][key] = value
+ result = True
+ else:
+ before_value = to_text(current_dict[key])
+ after_value = to_text(value)
+
+ if self.case_sensitive_keys and key in self.case_sensitive_keys:
+ if before_value != after_value:
+ if skip_diff_for_keys and key not in skip_diff_for_keys:
+ self.result['diff']['before'][key] = before_value
+ self.result['diff']['after'][key] = after_value
+ result = True
+
+ # Test for diff in case insensitive way
+ elif before_value.lower() != after_value.lower():
+ if skip_diff_for_keys and key not in skip_diff_for_keys:
+ self.result['diff']['before'][key] = before_value
+ self.result['diff']['after'][key] = after_value
+ result = True
+ else:
+ if skip_diff_for_keys and key not in skip_diff_for_keys:
+ self.result['diff']['before'][key] = None
+ self.result['diff']['after'][key] = to_text(value)
+ result = True
+ return result
+
+ def _get_by_key(self, key=None, my_dict=None):
+ if my_dict is None:
+ my_dict = {}
+ if key:
+ if key in my_dict:
+ return my_dict[key]
+ self.fail_json(msg="Something went wrong: %s not found" % key)
+ return my_dict
+
+ def query_api(self, command, **args):
+ try:
+ res = getattr(self.cs, command)(**args)
+
+ if 'errortext' in res:
+ self.fail_json(msg="Failed: '%s'" % res['errortext'])
+
+ except CloudStackException as e:
+ self.fail_json(msg='CloudStackException: %s' % to_native(e))
+
+ except Exception as e:
+ self.fail_json(msg=to_native(e))
+
+ return res
+
+ def get_network_acl(self, key=None):
+ if self.network_acl is None:
+ args = {
+ 'name': self.module.params.get('network_acl'),
+ 'vpcid': self.get_vpc(key='id'),
+ }
+ network_acls = self.query_api('listNetworkACLLists', **args)
+ if network_acls:
+ self.network_acl = network_acls['networkacllist'][0]
+ self.result['network_acl'] = self.network_acl['name']
+ if self.network_acl:
+ return self._get_by_key(key, self.network_acl)
+ else:
+ self.fail_json(msg="Network ACL %s not found" % self.module.params.get('network_acl'))
+
+ def get_vpc(self, key=None):
+ """Return a VPC dictionary or the value of given key of."""
+ if self.vpc:
+ return self._get_by_key(key, self.vpc)
+
+ vpc = self.module.params.get('vpc')
+ if not vpc:
+ vpc = os.environ.get('CLOUDSTACK_VPC')
+ if not vpc:
+ return None
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ }
+ vpcs = self.query_api('listVPCs', **args)
+ if not vpcs:
+ self.fail_json(msg="No VPCs available.")
+
+ for v in vpcs['vpc']:
+ if vpc in [v['name'], v['displaytext'], v['id']]:
+ # Fail if the identifyer matches more than one VPC
+ if self.vpc:
+ self.fail_json(msg="More than one VPC found with the provided identifyer '%s'" % vpc)
+ else:
+ self.vpc = v
+ self.result['vpc'] = v['name']
+ if self.vpc:
+ return self._get_by_key(key, self.vpc)
+ self.fail_json(msg="VPC '%s' not found" % vpc)
+
+ def is_vpc_network(self, network_id):
+ """Returns True if network is in VPC."""
+ # This is an efficient way to query a lot of networks at a time
+ if self._vpc_networks_ids is None:
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ }
+ vpcs = self.query_api('listVPCs', **args)
+ self._vpc_networks_ids = []
+ if vpcs:
+ for vpc in vpcs['vpc']:
+ for n in vpc.get('network', []):
+ self._vpc_networks_ids.append(n['id'])
+ return network_id in self._vpc_networks_ids
+
+ def get_physical_network(self, key=None):
+ if self.physical_network:
+ return self._get_by_key(key, self.physical_network)
+ physical_network = self.module.params.get('physical_network')
+ args = {
+ 'zoneid': self.get_zone(key='id')
+ }
+ physical_networks = self.query_api('listPhysicalNetworks', **args)
+ if not physical_networks:
+ self.fail_json(msg="No physical networks available.")
+
+ for net in physical_networks['physicalnetwork']:
+ if physical_network in [net['name'], net['id']]:
+ self.physical_network = net
+ self.result['physical_network'] = net['name']
+ return self._get_by_key(key, self.physical_network)
+ self.fail_json(msg="Physical Network '%s' not found" % physical_network)
+
+ def get_network(self, key=None):
+ """Return a network dictionary or the value of given key of."""
+ if self.network:
+ return self._get_by_key(key, self.network)
+
+ network = self.module.params.get('network')
+ if not network:
+ vpc_name = self.get_vpc(key='name')
+ if vpc_name:
+ self.fail_json(msg="Could not find network for VPC '%s' due missing argument: network" % vpc_name)
+ return None
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'vpcid': self.get_vpc(key='id')
+ }
+ networks = self.query_api('listNetworks', **args)
+ if not networks:
+ self.fail_json(msg="No networks available.")
+
+ for n in networks['network']:
+ # ignore any VPC network if vpc param is not given
+ if 'vpcid' in n and not self.get_vpc(key='id'):
+ continue
+ if network in [n['displaytext'], n['name'], n['id']]:
+ self.result['network'] = n['name']
+ self.network = n
+ return self._get_by_key(key, self.network)
+ self.fail_json(msg="Network '%s' not found" % network)
+
+ def get_project(self, key=None):
+ if self.project:
+ return self._get_by_key(key, self.project)
+
+ project = self.module.params.get('project')
+ if not project:
+ project = os.environ.get('CLOUDSTACK_PROJECT')
+ if not project:
+ return None
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id')
+ }
+ projects = self.query_api('listProjects', **args)
+ if projects:
+ for p in projects['project']:
+ if project.lower() in [p['name'].lower(), p['id']]:
+ self.result['project'] = p['name']
+ self.project = p
+ return self._get_by_key(key, self.project)
+ self.fail_json(msg="project '%s' not found" % project)
+
+ def get_pod(self, key=None):
+ pod_name = self.module.params.get('pod')
+ if not pod_name:
+ return None
+ args = {
+ 'name': pod_name,
+ 'zoneid': self.get_zone(key='id'),
+ }
+ pods = self.query_api('listPods', **args)
+ if pods:
+ return self._get_by_key(key, pods['pod'][0])
+ self.module.fail_json(msg="Pod %s not found in zone %s" % (self.module.params.get('pod'), self.get_zone(key='name')))
+
+ def get_ip_address(self, key=None):
+ if self.ip_address:
+ return self._get_by_key(key, self.ip_address)
+
+ ip_address = self.module.params.get('ip_address')
+ if not ip_address:
+ self.fail_json(msg="IP address param 'ip_address' is required")
+
+ args = {
+ 'ipaddress': ip_address,
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'vpcid': self.get_vpc(key='id'),
+ }
+
+ ip_addresses = self.query_api('listPublicIpAddresses', **args)
+
+ if not ip_addresses:
+ self.fail_json(msg="IP address '%s' not found" % args['ipaddress'])
+
+ self.ip_address = ip_addresses['publicipaddress'][0]
+ return self._get_by_key(key, self.ip_address)
+
+ def get_vm_guest_ip(self):
+ vm_guest_ip = self.module.params.get('vm_guest_ip')
+ default_nic = self.get_vm_default_nic()
+
+ if not vm_guest_ip:
+ return default_nic['ipaddress']
+
+ for secondary_ip in default_nic['secondaryip']:
+ if vm_guest_ip == secondary_ip['ipaddress']:
+ return vm_guest_ip
+ self.fail_json(msg="Secondary IP '%s' not assigned to VM" % vm_guest_ip)
+
+ def get_vm_default_nic(self):
+ if self.vm_default_nic:
+ return self.vm_default_nic
+
+ nics = self.query_api('listNics', virtualmachineid=self.get_vm(key='id'))
+ if nics:
+ for n in nics['nic']:
+ if n['isdefault']:
+ self.vm_default_nic = n
+ return self.vm_default_nic
+ self.fail_json(msg="No default IP address of VM '%s' found" % self.module.params.get('vm'))
+
+ def get_vm(self, key=None, filter_zone=True):
+ if self.vm:
+ return self._get_by_key(key, self.vm)
+
+ vm = self.module.params.get('vm')
+ if not vm:
+ self.fail_json(msg="Virtual machine param 'vm' is required")
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id') if filter_zone else None,
+ 'fetch_list': True,
+ }
+ vms = self.query_api('listVirtualMachines', **args)
+ if vms:
+ for v in vms:
+ if vm.lower() in [v['name'].lower(), v['displayname'].lower(), v['id']]:
+ self.vm = v
+ return self._get_by_key(key, self.vm)
+ self.fail_json(msg="Virtual machine '%s' not found" % vm)
+
+ def get_disk_offering(self, key=None):
+ disk_offering = self.module.params.get('disk_offering')
+ if not disk_offering:
+ return None
+
+ # Do not add domain filter for disk offering listing.
+ disk_offerings = self.query_api('listDiskOfferings')
+ if disk_offerings:
+ for d in disk_offerings['diskoffering']:
+ if disk_offering in [d['displaytext'], d['name'], d['id']]:
+ return self._get_by_key(key, d)
+ self.fail_json(msg="Disk offering '%s' not found" % disk_offering)
+
+ def get_zone(self, key=None):
+ if self.zone:
+ return self._get_by_key(key, self.zone)
+
+ zone = self.module.params.get('zone')
+ if not zone:
+ zone = os.environ.get('CLOUDSTACK_ZONE')
+ zones = self.query_api('listZones')
+
+ if not zones:
+ self.fail_json(msg="No zones available. Please create a zone first")
+
+ # use the first zone if no zone param given
+ if not zone:
+ self.module.deprecate(
+ msg="Using first zone as default is deprecated because of unreliable API, zone needs to be defined.",
+ version="2.0.0",
+ collection_name="ngine_io.cloudstack"
+ )
+ self.zone = zones['zone'][0]
+ self.result['zone'] = self.zone['name']
+ return self._get_by_key(key, self.zone)
+
+ if zones:
+ for z in zones['zone']:
+ if zone.lower() in [z['name'].lower(), z['id']]:
+ self.result['zone'] = z['name']
+ self.zone = z
+ return self._get_by_key(key, self.zone)
+ self.fail_json(msg="zone '%s' not found" % zone)
+
+ def get_os_type(self, key=None):
+ if self.os_type:
+ return self._get_by_key(key, self.zone)
+
+ os_type = self.module.params.get('os_type')
+ if not os_type:
+ return None
+
+ os_types = self.query_api('listOsTypes')
+ if os_types:
+ for o in os_types['ostype']:
+ if os_type in [o['description'], o['id']]:
+ self.os_type = o
+ return self._get_by_key(key, self.os_type)
+ self.fail_json(msg="OS type '%s' not found" % os_type)
+
+ def get_hypervisor(self):
+ if self.hypervisor:
+ return self.hypervisor
+
+ hypervisor = self.module.params.get('hypervisor')
+ hypervisors = self.query_api('listHypervisors')
+
+ # use the first hypervisor if no hypervisor param given
+ if not hypervisor:
+ self.hypervisor = hypervisors['hypervisor'][0]['name']
+ return self.hypervisor
+
+ for h in hypervisors['hypervisor']:
+ if hypervisor.lower() == h['name'].lower():
+ self.hypervisor = h['name']
+ return self.hypervisor
+ self.fail_json(msg="Hypervisor '%s' not found" % hypervisor)
+
+ def get_account(self, key=None):
+ if self.account:
+ return self._get_by_key(key, self.account)
+
+ account = self.module.params.get('account')
+ if not account:
+ account = os.environ.get('CLOUDSTACK_ACCOUNT')
+ if not account:
+ return None
+
+ domain = self.module.params.get('domain')
+ if not domain:
+ self.fail_json(msg="Account must be specified with Domain")
+
+ args = {
+ 'name': account,
+ 'domainid': self.get_domain(key='id'),
+ 'listall': True
+ }
+ accounts = self.query_api('listAccounts', **args)
+ if accounts:
+ self.account = accounts['account'][0]
+ self.result['account'] = self.account['name']
+ return self._get_by_key(key, self.account)
+ self.fail_json(msg="Account '%s' not found" % account)
+
+ def get_domain(self, key=None):
+ if self.domain:
+ return self._get_by_key(key, self.domain)
+
+ domain = self.module.params.get('domain')
+ if not domain:
+ domain = os.environ.get('CLOUDSTACK_DOMAIN')
+ if not domain:
+ return None
+
+ args = {
+ 'listall': True,
+ }
+ domains = self.query_api('listDomains', **args)
+ if domains:
+ for d in domains['domain']:
+ if d['path'].lower() in [domain.lower(), "root/" + domain.lower(), "root" + domain.lower()]:
+ self.domain = d
+ self.result['domain'] = d['path']
+ return self._get_by_key(key, self.domain)
+ self.fail_json(msg="Domain '%s' not found" % domain)
+
+ def query_tags(self, resource, resource_type):
+ args = {
+ 'resourceid': resource['id'],
+ 'resourcetype': resource_type,
+ }
+ tags = self.query_api('listTags', **args)
+ return self.get_tags(resource=tags, key='tag')
+
+ def get_tags(self, resource=None, key='tags'):
+ existing_tags = []
+ for tag in resource.get(key) or []:
+ existing_tags.append({'key': tag['key'], 'value': tag['value']})
+ return existing_tags
+
+ def _process_tags(self, resource, resource_type, tags, operation="create"):
+ if tags:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ args = {
+ 'resourceids': resource['id'],
+ 'resourcetype': resource_type,
+ 'tags': tags,
+ }
+ if operation == "create":
+ response = self.query_api('createTags', **args)
+ else:
+ response = self.query_api('deleteTags', **args)
+ self.poll_job(response)
+
+ def _tags_that_should_exist_or_be_updated(self, resource, tags):
+ existing_tags = self.get_tags(resource)
+ return [tag for tag in tags if tag not in existing_tags]
+
+ def _tags_that_should_not_exist(self, resource, tags):
+ existing_tags = self.get_tags(resource)
+ return [tag for tag in existing_tags if tag not in tags]
+
+ def ensure_tags(self, resource, resource_type=None):
+ if not resource_type or not resource:
+ self.fail_json(msg="Error: Missing resource or resource_type for tags.")
+
+ if 'tags' in resource:
+ tags = self.module.params.get('tags')
+ if tags is not None:
+ self._process_tags(resource, resource_type, self._tags_that_should_not_exist(resource, tags), operation="delete")
+ self._process_tags(resource, resource_type, self._tags_that_should_exist_or_be_updated(resource, tags))
+ resource['tags'] = self.query_tags(resource=resource, resource_type=resource_type)
+ return resource
+
+ def get_capabilities(self, key=None):
+ if self.capabilities:
+ return self._get_by_key(key, self.capabilities)
+ capabilities = self.query_api('listCapabilities')
+ self.capabilities = capabilities['capability']
+ return self._get_by_key(key, self.capabilities)
+
+ def poll_job(self, job=None, key=None):
+ if 'jobid' in job:
+ while True:
+ res = self.query_api('queryAsyncJobResult', jobid=job['jobid'])
+ if res['jobstatus'] != 0 and 'jobresult' in res:
+
+ if 'errortext' in res['jobresult']:
+ self.fail_json(msg="Failed: '%s'" % res['jobresult']['errortext'])
+
+ if key and key in res['jobresult']:
+ job = res['jobresult'][key]
+
+ break
+ time.sleep(2)
+ return job
+
+ def update_result(self, resource, result=None):
+ if result is None:
+ result = dict()
+ if resource:
+ returns = self.common_returns.copy()
+ returns.update(self.returns)
+ for search_key, return_key in returns.items():
+ if search_key in resource:
+ result[return_key] = resource[search_key]
+
+ # Bad bad API does not always return int when it should.
+ for search_key, return_key in self.returns_to_int.items():
+ if search_key in resource:
+ result[return_key] = int(resource[search_key])
+
+ if 'tags' in resource:
+ result['tags'] = resource['tags']
+ return result
+
+ def get_result(self, resource):
+ return self.update_result(resource, self.result)
+
+ def get_result_and_facts(self, facts_name, resource):
+ result = self.get_result(resource)
+
+ ansible_facts = {
+ facts_name: result.copy()
+ }
+ for k in ['diff', 'changed']:
+ if k in ansible_facts[facts_name]:
+ del ansible_facts[facts_name][k]
+
+ result.update(ansible_facts=ansible_facts)
+ return result
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/__init__.py
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_account.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_account.py
new file mode 100644
index 00000000..694f62d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_account.py
@@ -0,0 +1,450 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_account
+short_description: Manages accounts on Apache CloudStack based clouds.
+description:
+ - Create, disable, lock, enable and remove accounts.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of account.
+ type: str
+ required: true
+ username:
+ description:
+ - Username of the user to be created if account did not exist.
+ - Required on I(state=present).
+ type: str
+ password:
+ description:
+ - Password of the user to be created if account did not exist.
+ - Required on I(state=present) if I(ldap_domain) is not set.
+ type: str
+ first_name:
+ description:
+ - First name of the user to be created if account did not exist.
+ - Required on I(state=present) if I(ldap_domain) is not set.
+ type: str
+ last_name:
+ description:
+ - Last name of the user to be created if account did not exist.
+ - Required on I(state=present) if I(ldap_domain) is not set.
+ type: str
+ email:
+ description:
+ - Email of the user to be created if account did not exist.
+ - Required on I(state=present) if I(ldap_domain) is not set.
+ type: str
+ timezone:
+ description:
+ - Timezone of the user to be created if account did not exist.
+ type: str
+ network_domain:
+ description:
+ - Network domain of the account.
+ type: str
+ account_type:
+ description:
+ - Type of the account.
+ type: str
+ choices: [ user, root_admin, domain_admin ]
+ default: user
+ domain:
+ description:
+ - Domain the account is related to.
+ type: str
+ default: ROOT
+ role:
+ description:
+ - Creates the account under the specified role name or id.
+ type: str
+ ldap_domain:
+ description:
+ - Name of the LDAP group or OU to bind.
+ - If set, account will be linked to LDAP.
+ type: str
+ ldap_type:
+ description:
+ - Type of the ldap name. GROUP or OU, defaults to GROUP.
+ type: str
+ choices: [ GROUP, OU ]
+ default: GROUP
+ state:
+ description:
+ - State of the account.
+ - C(unlocked) is an alias for C(enabled).
+ type: str
+ choices: [ present, absent, enabled, disabled, locked, unlocked ]
+ default: present
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+
+'''
+
+EXAMPLES = '''
+- name: create an account in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_account:
+ name: customer_xy
+ username: customer_xy
+ password: S3Cur3
+ last_name: Doe
+ first_name: John
+ email: john.doe@example.com
+ domain: CUSTOMERS
+ role: Domain Admin
+
+- name: Lock an existing account in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_account:
+ name: customer_xy
+ domain: CUSTOMERS
+ state: locked
+
+- name: Disable an existing account in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_account:
+ name: customer_xy
+ domain: CUSTOMERS
+ state: disabled
+
+- name: Enable an existing account in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_account:
+ name: customer_xy
+ domain: CUSTOMERS
+ state: enabled
+
+- name: Remove an account in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_account:
+ name: customer_xy
+ domain: CUSTOMERS
+ state: absent
+
+- name: Create a single user LDAP account in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_account:
+ name: customer_xy
+ username: customer_xy
+ domain: CUSTOMERS
+ ldap_domain: cn=customer_xy,cn=team_xy,ou=People,dc=domain,dc=local
+
+- name: Create a LDAP account in domain 'CUSTOMERS' and bind it to a LDAP group
+ ngine_io.cloudstack.cs_account:
+ name: team_xy
+ username: customer_xy
+ domain: CUSTOMERS
+ ldap_domain: cn=team_xy,ou=People,dc=domain,dc=local
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the account.
+ returned: success
+ type: str
+ sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8
+name:
+ description: Name of the account.
+ returned: success
+ type: str
+ sample: linus@example.com
+account_type:
+ description: Type of the account.
+ returned: success
+ type: str
+ sample: user
+state:
+ description: State of the account.
+ returned: success
+ type: str
+ sample: enabled
+network_domain:
+ description: Network domain of the account.
+ returned: success
+ type: str
+ sample: example.local
+domain:
+ description: Domain the account is related.
+ returned: success
+ type: str
+ sample: ROOT
+role:
+ description: The role name of the account
+ returned: success
+ type: str
+ sample: Domain Admin
+'''
+
+# import cloudstack common
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackAccount(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackAccount, self).__init__(module)
+ self.returns = {
+ 'networkdomain': 'network_domain',
+ 'rolename': 'role',
+ }
+ self.account = None
+ self.account_types = {
+ 'user': 0,
+ 'root_admin': 1,
+ 'domain_admin': 2,
+ }
+
+ def get_role_id(self):
+ role_param = self.module.params.get('role')
+ role_id = None
+
+ if role_param:
+ role_list = self.query_api('listRoles')
+ for role in role_list['role']:
+ if role_param in [role['name'], role['id']]:
+ role_id = role['id']
+
+ if not role_id:
+ self.module.fail_json(msg="Role not found: %s" % role_param)
+
+ return role_id
+
+ def get_account_type(self):
+ account_type = self.module.params.get('account_type')
+ return self.account_types[account_type]
+
+ def get_account(self):
+ if not self.account:
+ args = {
+ 'listall': True,
+ 'domainid': self.get_domain(key='id'),
+ 'fetch_list': True,
+ }
+ accounts = self.query_api('listAccounts', **args)
+ if accounts:
+ account_name = self.module.params.get('name')
+ for a in accounts:
+ if account_name == a['name']:
+ self.account = a
+ break
+
+ return self.account
+
+ def enable_account(self):
+ account = self.get_account()
+ if not account:
+ account = self.present_account()
+
+ if account['state'].lower() != 'enabled':
+ self.result['changed'] = True
+ args = {
+ 'id': account['id'],
+ 'account': self.module.params.get('name'),
+ 'domainid': self.get_domain(key='id')
+ }
+ if not self.module.check_mode:
+ res = self.query_api('enableAccount', **args)
+ account = res['account']
+ return account
+
+ def lock_account(self):
+ return self.lock_or_disable_account(lock=True)
+
+ def disable_account(self):
+ return self.lock_or_disable_account()
+
+ def lock_or_disable_account(self, lock=False):
+ account = self.get_account()
+ if not account:
+ account = self.present_account()
+
+ # we need to enable the account to lock it.
+ if lock and account['state'].lower() == 'disabled':
+ account = self.enable_account()
+
+ if (lock and account['state'].lower() != 'locked' or
+ not lock and account['state'].lower() != 'disabled'):
+ self.result['changed'] = True
+ args = {
+ 'id': account['id'],
+ 'account': self.module.params.get('name'),
+ 'domainid': self.get_domain(key='id'),
+ 'lock': lock,
+ }
+ if not self.module.check_mode:
+ account = self.query_api('disableAccount', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ account = self.poll_job(account, 'account')
+ return account
+
+ def present_account(self):
+ account = self.get_account()
+
+ if not account:
+ self.result['changed'] = True
+
+ if self.module.params.get('ldap_domain'):
+ required_params = [
+ 'domain',
+ 'username',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ account = self.create_ldap_account(account)
+
+ else:
+ required_params = [
+ 'email',
+ 'username',
+ 'password',
+ 'first_name',
+ 'last_name',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ account = self.create_account(account)
+
+ return account
+
+ def create_ldap_account(self, account):
+ args = {
+ 'account': self.module.params.get('name'),
+ 'domainid': self.get_domain(key='id'),
+ 'accounttype': self.get_account_type(),
+ 'networkdomain': self.module.params.get('network_domain'),
+ 'username': self.module.params.get('username'),
+ 'timezone': self.module.params.get('timezone'),
+ 'roleid': self.get_role_id()
+ }
+ if not self.module.check_mode:
+ res = self.query_api('ldapCreateAccount', **args)
+ account = res['account']
+
+ args = {
+ 'account': self.module.params.get('name'),
+ 'domainid': self.get_domain(key='id'),
+ 'accounttype': self.get_account_type(),
+ 'ldapdomain': self.module.params.get('ldap_domain'),
+ 'type': self.module.params.get('ldap_type')
+ }
+
+ self.query_api('linkAccountToLdap', **args)
+
+ return account
+
+ def create_account(self, account):
+ args = {
+ 'account': self.module.params.get('name'),
+ 'domainid': self.get_domain(key='id'),
+ 'accounttype': self.get_account_type(),
+ 'networkdomain': self.module.params.get('network_domain'),
+ 'username': self.module.params.get('username'),
+ 'password': self.module.params.get('password'),
+ 'firstname': self.module.params.get('first_name'),
+ 'lastname': self.module.params.get('last_name'),
+ 'email': self.module.params.get('email'),
+ 'timezone': self.module.params.get('timezone'),
+ 'roleid': self.get_role_id()
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createAccount', **args)
+ account = res['account']
+
+ return account
+
+ def absent_account(self):
+ account = self.get_account()
+ if account:
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('deleteAccount', id=account['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'account')
+ return account
+
+ def get_result(self, account):
+ super(AnsibleCloudStackAccount, self).get_result(account)
+ if account:
+ if 'accounttype' in account:
+ for key, value in self.account_types.items():
+ if value == account['accounttype']:
+ self.result['account_type'] = key
+ break
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ state=dict(choices=['present', 'absent', 'enabled', 'disabled', 'locked', 'unlocked'], default='present'),
+ account_type=dict(choices=['user', 'root_admin', 'domain_admin'], default='user'),
+ network_domain=dict(),
+ domain=dict(default='ROOT'),
+ email=dict(),
+ first_name=dict(),
+ last_name=dict(),
+ username=dict(),
+ password=dict(no_log=True),
+ timezone=dict(),
+ role=dict(),
+ ldap_domain=dict(),
+ ldap_type=dict(choices=['GROUP', 'OU'], default='GROUP'),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_acc = AnsibleCloudStackAccount(module)
+
+ state = module.params.get('state')
+
+ if state in ['absent']:
+ account = acs_acc.absent_account()
+
+ elif state in ['enabled', 'unlocked']:
+ account = acs_acc.enable_account()
+
+ elif state in ['disabled']:
+ account = acs_acc.disable_account()
+
+ elif state in ['locked']:
+ account = acs_acc.lock_account()
+
+ else:
+ account = acs_acc.present_account()
+
+ result = acs_acc.get_result(account)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_affinitygroup.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_affinitygroup.py
new file mode 100644
index 00000000..46c1b176
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_affinitygroup.py
@@ -0,0 +1,230 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_affinitygroup
+short_description: Manages affinity groups on Apache CloudStack based clouds.
+description:
+ - Create and remove affinity groups.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the affinity group.
+ type: str
+ required: true
+ affinity_type:
+ description:
+ - Type of the affinity group. If not specified, first found affinity type is used.
+ type: str
+ description:
+ description:
+ - Description of the affinity group.
+ type: str
+ state:
+ description:
+ - State of the affinity group.
+ type: str
+ choices: [ present, absent ]
+ default: present
+ domain:
+ description:
+ - Domain the affinity group is related to.
+ type: str
+ account:
+ description:
+ - Account the affinity group is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the affinity group is related to.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+
+'''
+
+EXAMPLES = '''
+- name: Create a affinity group
+ ngine_io.cloudstack.cs_affinitygroup:
+ name: haproxy
+ affinity_type: host anti-affinity
+
+- name: Remove a affinity group
+ ngine_io.cloudstack.cs_affinitygroup:
+ name: haproxy
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the affinity group.
+ returned: success
+ type: str
+ sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8
+name:
+ description: Name of affinity group.
+ returned: success
+ type: str
+ sample: app
+description:
+ description: Description of affinity group.
+ returned: success
+ type: str
+ sample: application affinity group
+affinity_type:
+ description: Type of affinity group.
+ returned: success
+ type: str
+ sample: host anti-affinity
+project:
+ description: Name of project the affinity group is related to.
+ returned: success
+ type: str
+ sample: Production
+domain:
+ description: Domain the affinity group is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the affinity group is related to.
+ returned: success
+ type: str
+ sample: example account
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackAffinityGroup(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackAffinityGroup, self).__init__(module)
+ self.returns = {
+ 'type': 'affinity_type',
+ }
+ self.affinity_group = None
+
+ def get_affinity_group(self):
+ if not self.affinity_group:
+
+ args = {
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'name': self.module.params.get('name'),
+ }
+ affinity_groups = self.query_api('listAffinityGroups', **args)
+ if affinity_groups:
+ self.affinity_group = affinity_groups['affinitygroup'][0]
+ return self.affinity_group
+
+ def get_affinity_type(self):
+ affinity_type = self.module.params.get('affinity_type')
+
+ affinity_types = self.query_api('listAffinityGroupTypes', )
+ if affinity_types:
+ if not affinity_type:
+ return affinity_types['affinityGroupType'][0]['type']
+
+ for a in affinity_types['affinityGroupType']:
+ if a['type'] == affinity_type:
+ return a['type']
+ self.module.fail_json(msg="affinity group type not found: %s" % affinity_type)
+
+ def create_affinity_group(self):
+ affinity_group = self.get_affinity_group()
+ if not affinity_group:
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'type': self.get_affinity_type(),
+ 'description': self.module.params.get('description'),
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createAffinityGroup', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ affinity_group = self.poll_job(res, 'affinitygroup')
+ return affinity_group
+
+ def remove_affinity_group(self):
+ affinity_group = self.get_affinity_group()
+ if affinity_group:
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('deleteAffinityGroup', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ self.poll_job(res, 'affinitygroup')
+ return affinity_group
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ affinity_type=dict(),
+ description=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_ag = AnsibleCloudStackAffinityGroup(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ affinity_group = acs_ag.remove_affinity_group()
+ else:
+ affinity_group = acs_ag.create_affinity_group()
+
+ result = acs_ag.get_result(affinity_group)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_cluster.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_cluster.py
new file mode 100644
index 00000000..88ea35f2
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_cluster.py
@@ -0,0 +1,375 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_cluster
+short_description: Manages host clusters on Apache CloudStack based clouds.
+description:
+ - Create, update and remove clusters.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - name of the cluster.
+ type: str
+ required: true
+ zone:
+ description:
+ - Name of the zone in which the cluster belongs to.
+ - If not set, default zone is used.
+ type: str
+ pod:
+ description:
+ - Name of the pod in which the cluster belongs to.
+ type: str
+ cluster_type:
+ description:
+ - Type of the cluster.
+ - Required if I(state=present)
+ type: str
+ choices: [ CloudManaged, ExternalManaged ]
+ hypervisor:
+ description:
+ - Name the hypervisor to be used.
+ - Required if I(state=present).
+ - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator).
+ type: str
+ url:
+ description:
+ - URL for the cluster
+ type: str
+ username:
+ description:
+ - Username for the cluster.
+ type: str
+ password:
+ description:
+ - Password for the cluster.
+ type: str
+ guest_vswitch_name:
+ description:
+ - Name of virtual switch used for guest traffic in the cluster.
+ - This would override zone wide traffic label setting.
+ type: str
+ guest_vswitch_type:
+ description:
+ - Type of virtual switch used for guest traffic in the cluster.
+ - Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch)
+ type: str
+ choices: [ vmwaresvs, vmwaredvs ]
+ public_vswitch_name:
+ description:
+ - Name of virtual switch used for public traffic in the cluster.
+ - This would override zone wide traffic label setting.
+ type: str
+ public_vswitch_type:
+ description:
+ - Type of virtual switch used for public traffic in the cluster.
+ - Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch)
+ type: str
+ choices: [ vmwaresvs, vmwaredvs ]
+ vms_ip_address:
+ description:
+ - IP address of the VSM associated with this cluster.
+ type: str
+ vms_username:
+ description:
+ - Username for the VSM associated with this cluster.
+ type: str
+ vms_password:
+ description:
+ - Password for the VSM associated with this cluster.
+ type: str
+ ovm3_cluster:
+ description:
+ - Ovm3 native OCFS2 clustering enabled for cluster.
+ type: str
+ ovm3_pool:
+ description:
+ - Ovm3 native pooling enabled for cluster.
+ type: str
+ ovm3_vip:
+ description:
+ - Ovm3 vip to use for pool (and cluster).
+ type: str
+ state:
+ description:
+ - State of the cluster.
+ type: str
+ choices: [ present, absent, disabled, enabled ]
+ default: present
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Ensure a cluster is present
+ ngine_io.cloudstack.cs_cluster:
+ name: kvm-cluster-01
+ zone: ch-zrh-ix-01
+ hypervisor: KVM
+ cluster_type: CloudManaged
+
+- name: Ensure a cluster is disabled
+ ngine_io.cloudstack.cs_cluster:
+ name: kvm-cluster-01
+ zone: ch-zrh-ix-01
+ state: disabled
+
+- name: Ensure a cluster is enabled
+ ngine_io.cloudstack.cs_cluster:
+ name: kvm-cluster-01
+ zone: ch-zrh-ix-01
+ state: enabled
+
+- name: Ensure a cluster is absent
+ ngine_io.cloudstack.cs_cluster:
+ name: kvm-cluster-01
+ zone: ch-zrh-ix-01
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the cluster.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: Name of the cluster.
+ returned: success
+ type: str
+ sample: cluster01
+allocation_state:
+ description: State of the cluster.
+ returned: success
+ type: str
+ sample: Enabled
+cluster_type:
+ description: Type of the cluster.
+ returned: success
+ type: str
+ sample: ExternalManaged
+cpu_overcommit_ratio:
+ description: The CPU overcommit ratio of the cluster.
+ returned: success
+ type: str
+ sample: 1.0
+memory_overcommit_ratio:
+ description: The memory overcommit ratio of the cluster.
+ returned: success
+ type: str
+ sample: 1.0
+managed_state:
+ description: Whether this cluster is managed by CloudStack.
+ returned: success
+ type: str
+ sample: Managed
+ovm3_vip:
+ description: Ovm3 VIP to use for pooling and/or clustering
+ returned: success
+ type: str
+ sample: 10.10.10.101
+hypervisor:
+ description: Hypervisor of the cluster
+ returned: success
+ type: str
+ sample: VMware
+zone:
+ description: Name of zone the cluster is in.
+ returned: success
+ type: str
+ sample: ch-gva-2
+pod:
+ description: Name of pod the cluster is in.
+ returned: success
+ type: str
+ sample: pod01
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackCluster(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackCluster, self).__init__(module)
+ self.returns = {
+ 'allocationstate': 'allocation_state',
+ 'hypervisortype': 'hypervisor',
+ 'clustertype': 'cluster_type',
+ 'podname': 'pod',
+ 'managedstate': 'managed_state',
+ 'memoryovercommitratio': 'memory_overcommit_ratio',
+ 'cpuovercommitratio': 'cpu_overcommit_ratio',
+ 'ovm3vip': 'ovm3_vip',
+ }
+ self.cluster = None
+
+ def _get_common_cluster_args(self):
+ args = {
+ 'clustername': self.module.params.get('name'),
+ 'hypervisor': self.module.params.get('hypervisor'),
+ 'clustertype': self.module.params.get('cluster_type'),
+ }
+ state = self.module.params.get('state')
+ if state in ['enabled', 'disabled']:
+ args['allocationstate'] = state.capitalize()
+ return args
+
+ def get_cluster(self):
+ if not self.cluster:
+ args = {}
+
+ uuid = self.module.params.get('id')
+ if uuid:
+ args['id'] = uuid
+ clusters = self.query_api('listClusters', **args)
+ if clusters:
+ self.cluster = clusters['cluster'][0]
+ return self.cluster
+
+ args['name'] = self.module.params.get('name')
+ clusters = self.query_api('listClusters', **args)
+ if clusters:
+ self.cluster = clusters['cluster'][0]
+ # fix different return from API then request argument given
+ self.cluster['hypervisor'] = self.cluster['hypervisortype']
+ self.cluster['clustername'] = self.cluster['name']
+ return self.cluster
+
+ def present_cluster(self):
+ cluster = self.get_cluster()
+ if cluster:
+ cluster = self._update_cluster()
+ else:
+ cluster = self._create_cluster()
+ return cluster
+
+ def _create_cluster(self):
+ required_params = [
+ 'cluster_type',
+ 'hypervisor',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ args = self._get_common_cluster_args()
+ args['zoneid'] = self.get_zone(key='id')
+ args['podid'] = self.get_pod(key='id')
+ args['url'] = self.module.params.get('url')
+ args['username'] = self.module.params.get('username')
+ args['password'] = self.module.params.get('password')
+ args['guestvswitchname'] = self.module.params.get('guest_vswitch_name')
+ args['guestvswitchtype'] = self.module.params.get('guest_vswitch_type')
+ args['publicvswitchtype'] = self.module.params.get('public_vswitch_name')
+ args['publicvswitchtype'] = self.module.params.get('public_vswitch_type')
+ args['vsmipaddress'] = self.module.params.get('vms_ip_address')
+ args['vsmusername'] = self.module.params.get('vms_username')
+ args['vmspassword'] = self.module.params.get('vms_password')
+ args['ovm3cluster'] = self.module.params.get('ovm3_cluster')
+ args['ovm3pool'] = self.module.params.get('ovm3_pool')
+ args['ovm3vip'] = self.module.params.get('ovm3_vip')
+
+ self.result['changed'] = True
+
+ cluster = None
+ if not self.module.check_mode:
+ res = self.query_api('addCluster', **args)
+
+ # API returns a list as result CLOUDSTACK-9205
+ if isinstance(res['cluster'], list):
+ cluster = res['cluster'][0]
+ else:
+ cluster = res['cluster']
+ return cluster
+
+ def _update_cluster(self):
+ cluster = self.get_cluster()
+
+ args = self._get_common_cluster_args()
+ args['id'] = cluster['id']
+
+ if self.has_changed(args, cluster):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('updateCluster', **args)
+ cluster = res['cluster']
+
+ return cluster
+
+ def absent_cluster(self):
+ cluster = self.get_cluster()
+ if cluster:
+ self.result['changed'] = True
+
+ args = {
+ 'id': cluster['id'],
+ }
+
+ if not self.module.check_mode:
+ self.query_api('deleteCluster', **args)
+
+ return cluster
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ zone=dict(),
+ pod=dict(),
+ cluster_type=dict(choices=['CloudManaged', 'ExternalManaged']),
+ hypervisor=dict(),
+ state=dict(choices=['present', 'enabled', 'disabled', 'absent'], default='present'),
+ url=dict(),
+ username=dict(),
+ password=dict(no_log=True),
+ guest_vswitch_name=dict(),
+ guest_vswitch_type=dict(choices=['vmwaresvs', 'vmwaredvs']),
+ public_vswitch_name=dict(),
+ public_vswitch_type=dict(choices=['vmwaresvs', 'vmwaredvs']),
+ vms_ip_address=dict(),
+ vms_username=dict(),
+ vms_password=dict(no_log=True),
+ ovm3_cluster=dict(),
+ ovm3_pool=dict(),
+ ovm3_vip=dict(),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_cluster = AnsibleCloudStackCluster(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ cluster = acs_cluster.absent_cluster()
+ else:
+ cluster = acs_cluster.present_cluster()
+
+ result = acs_cluster.get_result(cluster)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_configuration.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_configuration.py
new file mode 100644
index 00000000..dd11d932
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_configuration.py
@@ -0,0 +1,270 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_configuration
+short_description: Manages configuration on Apache CloudStack based clouds.
+description:
+ - Manages global, zone, account, storage and cluster configurations.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the configuration.
+ type: str
+ required: true
+ value:
+ description:
+ - Value of the configuration.
+ type: str
+ required: true
+ account:
+ description:
+ - Ensure the value for corresponding account.
+ type: str
+ domain:
+ description:
+ - Domain the account is related to.
+ - Only considered if I(account) is used.
+ type: str
+ default: ROOT
+ zone:
+ description:
+ - Ensure the value for corresponding zone.
+ type: str
+ storage:
+ description:
+ - Ensure the value for corresponding storage pool.
+ type: str
+ cluster:
+ description:
+ - Ensure the value for corresponding cluster.
+ type: str
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Ensure global configuration
+ ngine_io.cloudstack.cs_configuration:
+ name: router.reboot.when.outofband.migrated
+ value: false
+
+- name: Ensure zone configuration
+ ngine_io.cloudstack.cs_configuration:
+ name: router.reboot.when.outofband.migrated
+ zone: ch-gva-01
+ value: true
+
+- name: Ensure storage configuration
+ ngine_io.cloudstack.cs_configuration:
+ name: storage.overprovisioning.factor
+ storage: storage01
+ value: 2.0
+
+- name: Ensure account configuration
+ ngine_io.cloudstack.cs_configuration:
+ name: allow.public.user.templates
+ value: false
+ account: acme inc
+ domain: customers
+'''
+
+RETURN = '''
+---
+category:
+ description: Category of the configuration.
+ returned: success
+ type: str
+ sample: Advanced
+scope:
+ description: Scope (zone/cluster/storagepool/account) of the parameter that needs to be updated.
+ returned: success
+ type: str
+ sample: storagepool
+description:
+ description: Description of the configuration.
+ returned: success
+ type: str
+ sample: Setup the host to do multipath
+name:
+ description: Name of the configuration.
+ returned: success
+ type: str
+ sample: zone.vlan.capacity.notificationthreshold
+value:
+ description: Value of the configuration.
+ returned: success
+ type: str
+ sample: "0.75"
+account:
+ description: Account of the configuration.
+ returned: success
+ type: str
+ sample: admin
+Domain:
+ description: Domain of account of the configuration.
+ returned: success
+ type: str
+ sample: ROOT
+zone:
+ description: Zone of the configuration.
+ returned: success
+ type: str
+ sample: ch-gva-01
+cluster:
+ description: Cluster of the configuration.
+ returned: success
+ type: str
+ sample: cluster01
+storage:
+ description: Storage of the configuration.
+ returned: success
+ type: str
+ sample: storage01
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackConfiguration(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackConfiguration, self).__init__(module)
+ self.returns = {
+ 'category': 'category',
+ 'scope': 'scope',
+ 'value': 'value',
+ }
+ self.storage = None
+ self.account = None
+ self.cluster = None
+
+ def _get_common_configuration_args(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'accountid': self.get_account(key='id'),
+ 'storageid': self.get_storage(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'clusterid': self.get_cluster(key='id'),
+ }
+ return args
+
+ def get_zone(self, key=None):
+ # make sure we do net use the default zone
+ zone = self.module.params.get('zone')
+ if zone:
+ return super(AnsibleCloudStackConfiguration, self).get_zone(key=key)
+
+ def get_cluster(self, key=None):
+ if not self.cluster:
+ cluster_name = self.module.params.get('cluster')
+ if not cluster_name:
+ return None
+ args = {
+ 'name': cluster_name,
+ }
+ clusters = self.query_api('listClusters', **args)
+ if clusters:
+ self.cluster = clusters['cluster'][0]
+ self.result['cluster'] = self.cluster['name']
+ else:
+ self.module.fail_json(msg="Cluster %s not found." % cluster_name)
+ return self._get_by_key(key=key, my_dict=self.cluster)
+
+ def get_storage(self, key=None):
+ if not self.storage:
+ storage_pool_name = self.module.params.get('storage')
+ if not storage_pool_name:
+ return None
+ args = {
+ 'name': storage_pool_name,
+ }
+ storage_pools = self.query_api('listStoragePools', **args)
+ if storage_pools:
+ self.storage = storage_pools['storagepool'][0]
+ self.result['storage'] = self.storage['name']
+ else:
+ self.module.fail_json(msg="Storage pool %s not found." % storage_pool_name)
+ return self._get_by_key(key=key, my_dict=self.storage)
+
+ def get_configuration(self):
+ configuration = None
+ args = self._get_common_configuration_args()
+ args['fetch_list'] = True
+ configurations = self.query_api('listConfigurations', **args)
+ if not configurations:
+ self.module.fail_json(msg="Configuration %s not found." % args['name'])
+ for config in configurations:
+ if args['name'] == config['name']:
+ configuration = config
+ return configuration
+
+ def get_value(self):
+ value = str(self.module.params.get('value'))
+ if value in ('True', 'False'):
+ value = value.lower()
+ return value
+
+ def present_configuration(self):
+ configuration = self.get_configuration()
+ args = self._get_common_configuration_args()
+ args['value'] = self.get_value()
+ empty_value = args['value'] in [None, ''] and 'value' not in configuration
+ if self.has_changed(args, configuration, ['value']) and not empty_value:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateConfiguration', **args)
+ configuration = res['configuration']
+ return configuration
+
+ def get_result(self, configuration):
+ self.result = super(AnsibleCloudStackConfiguration, self).get_result(configuration)
+ if self.account:
+ self.result['account'] = self.account['name']
+ self.result['domain'] = self.domain['path']
+ elif self.zone:
+ self.result['zone'] = self.zone['name']
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ value=dict(type='str', required=True),
+ zone=dict(),
+ storage=dict(),
+ cluster=dict(),
+ account=dict(),
+ domain=dict(default='ROOT')
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_configuration = AnsibleCloudStackConfiguration(module)
+ configuration = acs_configuration.present_configuration()
+ result = acs_configuration.get_result(configuration)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_disk_offering.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_disk_offering.py
new file mode 100644
index 00000000..b9bd4570
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_disk_offering.py
@@ -0,0 +1,375 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2018, David Passante <@dpassante>
+# Copyright (c) 2017, 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: cs_disk_offering
+description:
+ - Create and delete disk offerings for guest VMs.
+ - Update display_text or display_offering of existing disk offering.
+short_description: Manages disk offerings on Apache CloudStack based clouds.
+author:
+ - David Passante (@dpassante)
+ - René Moser (@resmo)
+version_added: 0.1.0
+options:
+ disk_size:
+ description:
+ - Size of the disk offering in GB (1GB = 1,073,741,824 bytes).
+ type: int
+ bytes_read_rate:
+ description:
+ - Bytes read rate of the disk offering.
+ type: int
+ bytes_write_rate:
+ description:
+ - Bytes write rate of the disk offering.
+ type: int
+ display_text:
+ description:
+ - Display text of the disk offering.
+ - If not set, C(name) will be used as C(display_text) while creating.
+ type: str
+ domain:
+ description:
+ - Domain the disk offering is related to.
+ - Public for all domains and subdomains if not set.
+ type: str
+ hypervisor_snapshot_reserve:
+ description:
+ - Hypervisor snapshot reserve space as a percent of a volume.
+ - Only for managed storage using Xen or VMware.
+ type: int
+ customized:
+ description:
+ - Whether disk offering iops is custom or not.
+ type: bool
+ iops_read_rate:
+ description:
+ - IO requests read rate of the disk offering.
+ type: int
+ iops_write_rate:
+ description:
+ - IO requests write rate of the disk offering.
+ type: int
+ iops_max:
+ description:
+ - Max. iops of the disk offering.
+ type: int
+ iops_min:
+ description:
+ - Min. iops of the disk offering.
+ type: int
+ name:
+ description:
+ - Name of the disk offering.
+ type: str
+ required: true
+ provisioning_type:
+ description:
+ - Provisioning type used to create volumes.
+ type: str
+ choices: [ thin, sparse, fat ]
+ state:
+ description:
+ - State of the disk offering.
+ type: str
+ choices: [ present, absent ]
+ default: present
+ storage_type:
+ description:
+ - The storage type of the disk offering.
+ type: str
+ choices: [ local, shared ]
+ storage_tags:
+ description:
+ - The storage tags for this disk offering.
+ type: list
+ elements: str
+ aliases: [ storage_tag ]
+ display_offering:
+ description:
+ - An optional field, whether to display the offering to the end user or not.
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a disk offering with local storage
+ ngine_io.cloudstack.cs_disk_offering:
+ name: small
+ display_text: Small 10GB
+ disk_size: 10
+ storage_type: local
+
+- name: Create or update a disk offering with shared storage
+ ngine_io.cloudstack.cs_disk_offering:
+ name: small
+ display_text: Small 10GB
+ disk_size: 10
+ storage_type: shared
+ storage_tags: SAN01
+
+- name: Remove a disk offering
+ ngine_io.cloudstack.cs_disk_offering:
+ name: small
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the disk offering
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+disk_size:
+ description: Size of the disk offering in GB
+ returned: success
+ type: int
+ sample: 10
+iops_max:
+ description: Max iops of the disk offering
+ returned: success
+ type: int
+ sample: 1000
+iops_min:
+ description: Min iops of the disk offering
+ returned: success
+ type: int
+ sample: 500
+bytes_read_rate:
+ description: Bytes read rate of the disk offering
+ returned: success
+ type: int
+ sample: 1000
+bytes_write_rate:
+ description: Bytes write rate of the disk offering
+ returned: success
+ type: int
+ sample: 1000
+iops_read_rate:
+ description: IO requests per second read rate of the disk offering
+ returned: success
+ type: int
+ sample: 1000
+iops_write_rate:
+ description: IO requests per second write rate of the disk offering
+ returned: success
+ type: int
+ sample: 1000
+created:
+ description: Date the offering was created
+ returned: success
+ type: str
+ sample: 2017-11-19T10:48:59+0000
+display_text:
+ description: Display text of the offering
+ returned: success
+ type: str
+ sample: Small 10GB
+domain:
+ description: Domain the offering is into
+ returned: success
+ type: str
+ sample: ROOT
+storage_tags:
+ description: List of storage tags
+ returned: success
+ type: list
+ sample: [ 'eco' ]
+customized:
+ description: Whether the offering uses custom IOPS or not
+ returned: success
+ type: bool
+ sample: false
+name:
+ description: Name of the system offering
+ returned: success
+ type: str
+ sample: Micro
+provisioning_type:
+ description: Provisioning type used to create volumes
+ returned: success
+ type: str
+ sample: thin
+storage_type:
+ description: Storage type used to create volumes
+ returned: success
+ type: str
+ sample: shared
+display_offering:
+ description: Whether to display the offering to the end user or not.
+ returned: success
+ type: bool
+ sample: false
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackDiskOffering(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackDiskOffering, self).__init__(module)
+ self.returns = {
+ 'disksize': 'disk_size',
+ 'diskBytesReadRate': 'bytes_read_rate',
+ 'diskBytesWriteRate': 'bytes_write_rate',
+ 'diskIopsReadRate': 'iops_read_rate',
+ 'diskIopsWriteRate': 'iops_write_rate',
+ 'maxiops': 'iops_max',
+ 'miniops': 'iops_min',
+ 'hypervisorsnapshotreserve': 'hypervisor_snapshot_reserve',
+ 'customized': 'customized',
+ 'provisioningtype': 'provisioning_type',
+ 'storagetype': 'storage_type',
+ 'tags': 'storage_tags',
+ 'displayoffering': 'display_offering',
+ }
+
+ self.disk_offering = None
+
+ def get_disk_offering(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'domainid': self.get_domain(key='id'),
+ }
+ disk_offerings = self.query_api('listDiskOfferings', **args)
+ if disk_offerings:
+ for disk_offer in disk_offerings['diskoffering']:
+ if args['name'] == disk_offer['name']:
+ self.disk_offering = disk_offer
+
+ return self.disk_offering
+
+ def present_disk_offering(self):
+ disk_offering = self.get_disk_offering()
+ if not disk_offering:
+ disk_offering = self._create_offering(disk_offering)
+ else:
+ disk_offering = self._update_offering(disk_offering)
+
+ return disk_offering
+
+ def absent_disk_offering(self):
+ disk_offering = self.get_disk_offering()
+ if disk_offering:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ args = {
+ 'id': disk_offering['id'],
+ }
+ self.query_api('deleteDiskOffering', **args)
+ return disk_offering
+
+ def _create_offering(self, disk_offering):
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ 'disksize': self.module.params.get('disk_size'),
+ 'bytesreadrate': self.module.params.get('bytes_read_rate'),
+ 'byteswriterate': self.module.params.get('bytes_write_rate'),
+ 'customized': self.module.params.get('customized'),
+ 'domainid': self.get_domain(key='id'),
+ 'hypervisorsnapshotreserve': self.module.params.get('hypervisor_snapshot_reserve'),
+ 'iopsreadrate': self.module.params.get('iops_read_rate'),
+ 'iopswriterate': self.module.params.get('iops_write_rate'),
+ 'maxiops': self.module.params.get('iops_max'),
+ 'miniops': self.module.params.get('iops_min'),
+ 'provisioningtype': self.module.params.get('provisioning_type'),
+ 'diskofferingdetails': self.module.params.get('disk_offering_details'),
+ 'storagetype': self.module.params.get('storage_type'),
+ 'tags': self.module.params.get('storage_tags'),
+ 'displayoffering': self.module.params.get('display_offering'),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createDiskOffering', **args)
+ disk_offering = res['diskoffering']
+ return disk_offering
+
+ def _update_offering(self, disk_offering):
+ args = {
+ 'id': disk_offering['id'],
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ 'displayoffering': self.module.params.get('display_offering'),
+ }
+ if self.has_changed(args, disk_offering):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('updateDiskOffering', **args)
+ disk_offering = res['diskoffering']
+ return disk_offering
+
+ def get_result(self, disk_offering):
+ super(AnsibleCloudStackDiskOffering, self).get_result(disk_offering)
+ if disk_offering:
+ # Prevent confusion, the api returns a tags key for storage tags.
+ if 'tags' in disk_offering:
+ self.result['storage_tags'] = disk_offering['tags'].split(',') or [disk_offering['tags']]
+ if 'tags' in self.result:
+ del self.result['tags']
+
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ display_text=dict(),
+ domain=dict(),
+ disk_size=dict(type='int'),
+ display_offering=dict(type='bool'),
+ hypervisor_snapshot_reserve=dict(type='int'),
+ bytes_read_rate=dict(type='int'),
+ bytes_write_rate=dict(type='int'),
+ customized=dict(type='bool'),
+ iops_read_rate=dict(type='int'),
+ iops_write_rate=dict(type='int'),
+ iops_max=dict(type='int'),
+ iops_min=dict(type='int'),
+ provisioning_type=dict(choices=['thin', 'sparse', 'fat']),
+ storage_type=dict(choices=['local', 'shared']),
+ storage_tags=dict(type='list', elements='str', aliases=['storage_tag']),
+ state=dict(choices=['present', 'absent'], default='present'),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_do = AnsibleCloudStackDiskOffering(module)
+
+ state = module.params.get('state')
+ if state == "absent":
+ disk_offering = acs_do.absent_disk_offering()
+ else:
+ disk_offering = acs_do.present_disk_offering()
+
+ result = acs_do.get_result(disk_offering)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_domain.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_domain.py
new file mode 100644
index 00000000..68177164
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_domain.py
@@ -0,0 +1,244 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_domain
+short_description: Manages domains on Apache CloudStack based clouds.
+description:
+ - Create, update and remove domains.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ path:
+ description:
+ - Path of the domain.
+ - Prefix C(ROOT/) or C(/ROOT/) in path is optional.
+ type: str
+ required: true
+ network_domain:
+ description:
+ - Network domain for networks in the domain.
+ type: str
+ clean_up:
+ description:
+ - Clean up all domain resources like child domains and accounts.
+ - Considered on I(state=absent).
+ type: bool
+ default: no
+ state:
+ description:
+ - State of the domain.
+ type: str
+ choices: [ present, absent ]
+ default: present
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a domain
+ ngine_io.cloudstack.cs_domain:
+ path: ROOT/customers
+ network_domain: customers.example.com
+
+- name: Create another subdomain
+ ngine_io.cloudstack.cs_domain:
+ path: ROOT/customers/xy
+ network_domain: xy.customers.example.com
+
+- name: Remove a domain
+ ngine_io.cloudstack.cs_domain:
+ path: ROOT/customers/xy
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the domain.
+ returned: success
+ type: str
+ sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8
+name:
+ description: Name of the domain.
+ returned: success
+ type: str
+ sample: customers
+path:
+ description: Domain path.
+ returned: success
+ type: str
+ sample: /ROOT/customers
+parent_domain:
+ description: Parent domain of the domain.
+ returned: success
+ type: str
+ sample: ROOT
+network_domain:
+ description: Network domain of the domain.
+ returned: success
+ type: str
+ sample: example.local
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackDomain(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackDomain, self).__init__(module)
+ self.returns = {
+ 'path': 'path',
+ 'networkdomain': 'network_domain',
+ 'parentdomainname': 'parent_domain',
+ }
+ self.domain = None
+
+ def _get_domain_internal(self, path=None):
+ if not path:
+ path = self.module.params.get('path')
+
+ if path.endswith('/'):
+ self.module.fail_json(msg="Path '%s' must not end with /" % path)
+
+ path = path.lower()
+
+ if path.startswith('/') and not path.startswith('/root/'):
+ path = "root" + path
+ elif not path.startswith('root/'):
+ path = "root/" + path
+
+ args = {
+ 'listall': True,
+ 'fetch_list': True,
+ }
+
+ domains = self.query_api('listDomains', **args)
+ if domains:
+ for d in domains:
+ if path == d['path'].lower():
+ return d
+ return None
+
+ def get_name(self):
+ # last part of the path is the name
+ name = self.module.params.get('path').split('/')[-1:]
+ return name
+
+ def get_domain(self, key=None):
+ if not self.domain:
+ self.domain = self._get_domain_internal()
+ return self._get_by_key(key, self.domain)
+
+ def get_parent_domain(self, key=None):
+ path = self.module.params.get('path')
+ # cut off last /*
+ path = '/'.join(path.split('/')[:-1])
+ if not path:
+ return None
+ parent_domain = self._get_domain_internal(path=path)
+ if not parent_domain:
+ self.module.fail_json(msg="Parent domain path %s does not exist" % path)
+ return self._get_by_key(key, parent_domain)
+
+ def present_domain(self):
+ domain = self.get_domain()
+ if not domain:
+ domain = self.create_domain(domain)
+ else:
+ domain = self.update_domain(domain)
+ return domain
+
+ def create_domain(self, domain):
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.get_name(),
+ 'parentdomainid': self.get_parent_domain(key='id'),
+ 'networkdomain': self.module.params.get('network_domain')
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createDomain', **args)
+ domain = res['domain']
+ return domain
+
+ def update_domain(self, domain):
+ args = {
+ 'id': domain['id'],
+ 'networkdomain': self.module.params.get('network_domain')
+ }
+ if self.has_changed(args, domain):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateDomain', **args)
+ domain = res['domain']
+ return domain
+
+ def absent_domain(self):
+ domain = self.get_domain()
+ if domain:
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ args = {
+ 'id': domain['id'],
+ 'cleanup': self.module.params.get('clean_up')
+ }
+ res = self.query_api('deleteDomain', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ res = self.poll_job(res, 'domain')
+ return domain
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ path=dict(required=True),
+ state=dict(choices=['present', 'absent'], default='present'),
+ network_domain=dict(),
+ clean_up=dict(type='bool', default=False),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_dom = AnsibleCloudStackDomain(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ domain = acs_dom.absent_domain()
+ else:
+ domain = acs_dom.present_domain()
+
+ result = acs_dom.get_result(domain)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_facts.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_facts.py
new file mode 100644
index 00000000..e60d5e80
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_facts.py
@@ -0,0 +1,231 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_facts
+short_description: Gather facts on instances of Apache CloudStack based clouds.
+description:
+ - This module fetches data from the metadata API in CloudStack. The module must be called from within the instance itself.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ filter:
+ description:
+ - Filter for a specific fact.
+ type: str
+ choices:
+ - cloudstack_service_offering
+ - cloudstack_availability_zone
+ - cloudstack_public_hostname
+ - cloudstack_public_ipv4
+ - cloudstack_local_hostname
+ - cloudstack_local_ipv4
+ - cloudstack_instance_id
+ - cloudstack_user_data
+ meta_data_host:
+ description:
+ - Host or IP of the meta data API service.
+ - If not set, determination by parsing the dhcp lease file.
+ type: str
+requirements: [ yaml ]
+'''
+
+EXAMPLES = '''
+# Gather all facts on instances
+- name: Gather cloudstack facts
+ ngine_io.cloudstack.cs_facts:
+
+# Gather specific fact on instances
+- name: Gather cloudstack facts
+ ngine_io.cloudstack.cs_facts: filter=cloudstack_instance_id
+
+# Gather specific fact on instances with a given meta_data_host
+- name: Gather cloudstack facts
+ ngine_io.cloudstack.cs_facts:
+ filter: cloudstack_instance_id
+ meta_data_host: 169.254.169.254
+'''
+
+RETURN = '''
+---
+cloudstack_availability_zone:
+ description: zone the instance is deployed in.
+ returned: success
+ type: str
+ sample: ch-gva-2
+cloudstack_instance_id:
+ description: UUID of the instance.
+ returned: success
+ type: str
+ sample: ab4e80b0-3e7e-4936-bdc5-e334ba5b0139
+cloudstack_local_hostname:
+ description: local hostname of the instance.
+ returned: success
+ type: str
+ sample: VM-ab4e80b0-3e7e-4936-bdc5-e334ba5b0139
+cloudstack_local_ipv4:
+ description: local IPv4 of the instance.
+ returned: success
+ type: str
+ sample: 185.19.28.35
+cloudstack_public_hostname:
+ description: public IPv4 of the router. Same as I(cloudstack_public_ipv4).
+ returned: success
+ type: str
+ sample: VM-ab4e80b0-3e7e-4936-bdc5-e334ba5b0139
+cloudstack_public_ipv4:
+ description: public IPv4 of the router.
+ returned: success
+ type: str
+ sample: 185.19.28.35
+cloudstack_service_offering:
+ description: service offering of the instance.
+ returned: success
+ type: str
+ sample: Micro 512mb 1cpu
+cloudstack_user_data:
+ description: data of the instance provided by users.
+ returned: success
+ type: dict
+ sample: { "bla": "foo" }
+'''
+
+import os
+import traceback
+from ansible.module_utils.basic import AnsibleModule, missing_required_lib
+from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.facts import ansible_collector, default_collectors
+
+YAML_IMP_ERR = None
+try:
+ import yaml
+ HAS_LIB_YAML = True
+except ImportError:
+ YAML_IMP_ERR = traceback.format_exc()
+ HAS_LIB_YAML = False
+
+CS_METADATA_BASE_URL = "http://%s/latest/meta-data"
+CS_USERDATA_BASE_URL = "http://%s/latest/user-data"
+
+
+class CloudStackFacts(object):
+
+ def __init__(self):
+ collector = ansible_collector.get_ansible_collector(all_collector_classes=default_collectors.collectors,
+ filter_spec='default_ipv4',
+ gather_subset=['!all', 'network'],
+ gather_timeout=10)
+ self.facts = collector.collect(module)
+
+ self.api_ip = None
+ self.fact_paths = {
+ 'cloudstack_service_offering': 'service-offering',
+ 'cloudstack_availability_zone': 'availability-zone',
+ 'cloudstack_public_hostname': 'public-hostname',
+ 'cloudstack_public_ipv4': 'public-ipv4',
+ 'cloudstack_local_hostname': 'local-hostname',
+ 'cloudstack_local_ipv4': 'local-ipv4',
+ 'cloudstack_instance_id': 'instance-id'
+ }
+
+ def run(self):
+ result = {}
+ filter = module.params.get('filter')
+ if not filter:
+ for key, path in self.fact_paths.items():
+ result[key] = self._fetch(CS_METADATA_BASE_URL + "/" + path)
+ result['cloudstack_user_data'] = self._get_user_data_json()
+ else:
+ if filter == 'cloudstack_user_data':
+ result['cloudstack_user_data'] = self._get_user_data_json()
+ elif filter in self.fact_paths:
+ result[filter] = self._fetch(CS_METADATA_BASE_URL + "/" + self.fact_paths[filter])
+ return result
+
+ def _get_user_data_json(self):
+ try:
+ # this data come form users, we try what we can to parse it...
+ return yaml.safe_load(self._fetch(CS_USERDATA_BASE_URL))
+ except Exception:
+ return None
+
+ def _fetch(self, path):
+ api_ip = self._get_api_ip()
+ if not api_ip:
+ return None
+ api_url = path % api_ip
+ (response, info) = fetch_url(module, api_url, force=True)
+ if response:
+ data = response.read()
+ else:
+ data = None
+ return data
+
+ def _get_dhcp_lease_file(self):
+ """Return the path of the lease file."""
+ default_iface = self.facts['default_ipv4']['interface']
+ dhcp_lease_file_locations = [
+ '/var/lib/dhcp/dhclient.%s.leases' % default_iface, # debian / ubuntu
+ '/var/lib/dhclient/dhclient-%s.leases' % default_iface, # centos 6
+ '/var/lib/dhclient/dhclient--%s.lease' % default_iface, # centos 7
+ '/var/db/dhclient.leases.%s' % default_iface, # openbsd
+ ]
+ for file_path in dhcp_lease_file_locations:
+ if os.path.exists(file_path):
+ return file_path
+ module.fail_json(msg="Could not find dhclient leases file.")
+
+ def _get_api_ip(self):
+ """Return the IP of the DHCP server."""
+ if module.params.get('meta_data_host'):
+ return module.params.get('meta_data_host')
+ elif not self.api_ip:
+ dhcp_lease_file = self._get_dhcp_lease_file()
+ for line in open(dhcp_lease_file):
+ if 'dhcp-server-identifier' in line:
+ # get IP of string "option dhcp-server-identifier 185.19.28.176;"
+ line = line.translate(None, ';')
+ self.api_ip = line.split()[2]
+ break
+ if not self.api_ip:
+ module.fail_json(msg="No dhcp-server-identifier found in leases file.")
+ return self.api_ip
+
+
+def main():
+ global module
+ module = AnsibleModule(
+ argument_spec=dict(
+ filter=dict(default=None, choices=[
+ 'cloudstack_service_offering',
+ 'cloudstack_availability_zone',
+ 'cloudstack_public_hostname',
+ 'cloudstack_public_ipv4',
+ 'cloudstack_local_hostname',
+ 'cloudstack_local_ipv4',
+ 'cloudstack_instance_id',
+ 'cloudstack_user_data',
+ ]),
+ meta_data_host=dict(),
+ ),
+ supports_check_mode=True
+ )
+
+ if not HAS_LIB_YAML:
+ module.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR)
+
+ cs_facts = CloudStackFacts().run()
+ cs_facts_result = dict(changed=False, ansible_facts=cs_facts)
+ module.exit_json(**cs_facts_result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_firewall.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_firewall.py
new file mode 100644
index 00000000..f8878877
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_firewall.py
@@ -0,0 +1,439 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright: (c) 2015, 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: cs_firewall
+short_description: Manages firewall rules on Apache CloudStack based clouds.
+description:
+ - Creates and removes firewall rules.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ ip_address:
+ description:
+ - Public IP address the ingress rule is assigned to.
+ - Required if I(type=ingress).
+ type: str
+ network:
+ description:
+ - Network the egress rule is related to.
+ - Required if I(type=egress).
+ type: str
+ state:
+ description:
+ - State of the firewall rule.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ type:
+ description:
+ - Type of the firewall rule.
+ type: str
+ default: ingress
+ choices: [ ingress, egress ]
+ protocol:
+ description:
+ - Protocol of the firewall rule.
+ - C(all) is only available if I(type=egress).
+ type: str
+ default: tcp
+ choices: [ tcp, udp, icmp, all ]
+ cidrs:
+ description:
+ - List of CIDRs (full notation) to be used for firewall rule.
+ - Since version 2.5, it is a list of CIDR.
+ elements: str
+ type: list
+ default: 0.0.0.0/0
+ aliases: [ cidr ]
+ start_port:
+ description:
+ - Start port for this rule.
+ - Considered if I(protocol=tcp) or I(protocol=udp).
+ type: int
+ aliases: [ port ]
+ end_port:
+ description:
+ - End port for this rule. Considered if I(protocol=tcp) or I(protocol=udp).
+ - If not specified, equal I(start_port).
+ type: int
+ icmp_type:
+ description:
+ - Type of the icmp message being sent.
+ - Considered if I(protocol=icmp).
+ type: int
+ icmp_code:
+ description:
+ - Error code for this icmp message.
+ - Considered if I(protocol=icmp).
+ type: int
+ domain:
+ description:
+ - Domain the firewall rule is related to.
+ type: str
+ account:
+ description:
+ - Account the firewall rule is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the firewall rule is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the virtual machine is in.
+ - If not set, default zone is used.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "To delete all tags, set an empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Allow inbound port 80/tcp from 1.2.3.4 to 4.3.2.1
+ ngine_io.cloudstack.cs_firewall:
+ ip_address: 4.3.2.1
+ port: 80
+ cidr: 1.2.3.4/32
+
+- name: Allow inbound tcp/udp port 53 to 4.3.2.1
+ ngine_io.cloudstack.cs_firewall:
+ ip_address: 4.3.2.1
+ port: 53
+ protocol: '{{ item }}'
+ with_items:
+ - tcp
+ - udp
+
+- name: Ensure firewall rule is removed
+ ngine_io.cloudstack.cs_firewall:
+ ip_address: 4.3.2.1
+ start_port: 8000
+ end_port: 8888
+ cidr: 17.0.0.0/8
+ state: absent
+
+- name: Allow all outbound traffic
+ ngine_io.cloudstack.cs_firewall:
+ network: my_network
+ type: egress
+ protocol: all
+
+- name: Allow only HTTP outbound traffic for an IP
+ ngine_io.cloudstack.cs_firewall:
+ network: my_network
+ type: egress
+ port: 80
+ cidr: 10.101.1.20
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the rule.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+ip_address:
+ description: IP address of the rule if C(type=ingress)
+ returned: success
+ type: str
+ sample: 10.100.212.10
+type:
+ description: Type of the rule.
+ returned: success
+ type: str
+ sample: ingress
+cidr:
+ description: CIDR string of the rule.
+ returned: success
+ type: str
+ sample: 0.0.0.0/0
+cidrs:
+ description: CIDR list of the rule.
+ returned: success
+ type: list
+ sample: [ '0.0.0.0/0' ]
+protocol:
+ description: Protocol of the rule.
+ returned: success
+ type: str
+ sample: tcp
+start_port:
+ description: Start port of the rule.
+ returned: success
+ type: int
+ sample: 80
+end_port:
+ description: End port of the rule.
+ returned: success
+ type: int
+ sample: 80
+icmp_code:
+ description: ICMP code of the rule.
+ returned: success
+ type: int
+ sample: 1
+icmp_type:
+ description: ICMP type of the rule.
+ returned: success
+ type: int
+ sample: 1
+network:
+ description: Name of the network if C(type=egress)
+ returned: success
+ type: str
+ sample: my_network
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackFirewall(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackFirewall, self).__init__(module)
+ self.returns = {
+ 'cidrlist': 'cidr',
+ 'startport': 'start_port',
+ 'endport': 'end_port',
+ 'protocol': 'protocol',
+ 'ipaddress': 'ip_address',
+ 'icmpcode': 'icmp_code',
+ 'icmptype': 'icmp_type',
+ }
+ self.firewall_rule = None
+ self.network = None
+
+ def get_firewall_rule(self):
+ if not self.firewall_rule:
+ cidrs = self.module.params.get('cidrs')
+ protocol = self.module.params.get('protocol')
+ start_port = self.module.params.get('start_port')
+ end_port = self.get_or_fallback('end_port', 'start_port')
+ icmp_code = self.module.params.get('icmp_code')
+ icmp_type = self.module.params.get('icmp_type')
+ fw_type = self.module.params.get('type')
+
+ if protocol in ['tcp', 'udp'] and not (start_port and end_port):
+ self.module.fail_json(msg="missing required argument for protocol '%s': start_port or end_port" % protocol)
+
+ if protocol == 'icmp' and not icmp_type:
+ self.module.fail_json(msg="missing required argument for protocol 'icmp': icmp_type")
+
+ if protocol == 'all' and fw_type != 'egress':
+ self.module.fail_json(msg="protocol 'all' could only be used for type 'egress'")
+
+ args = {
+ 'account': self.get_account('name'),
+ 'domainid': self.get_domain('id'),
+ 'projectid': self.get_project('id'),
+ 'fetch_list': True,
+ }
+ if fw_type == 'egress':
+ args['networkid'] = self.get_network(key='id')
+ if not args['networkid']:
+ self.module.fail_json(msg="missing required argument for type egress: network")
+
+ # CloudStack 4.11 use the network cidr for 0.0.0.0/0 in egress
+ # That is why we need to replace it.
+ network_cidr = self.get_network(key='cidr')
+ egress_cidrs = [network_cidr if cidr == '0.0.0.0/0' else cidr for cidr in cidrs]
+
+ firewall_rules = self.query_api('listEgressFirewallRules', **args)
+ else:
+ args['ipaddressid'] = self.get_ip_address('id')
+ if not args['ipaddressid']:
+ self.module.fail_json(msg="missing required argument for type ingress: ip_address")
+ egress_cidrs = None
+
+ firewall_rules = self.query_api('listFirewallRules', **args)
+
+ if firewall_rules:
+ for rule in firewall_rules:
+ type_match = self._type_cidrs_match(rule, cidrs, egress_cidrs)
+
+ protocol_match = (
+ self._tcp_udp_match(rule, protocol, start_port, end_port) or
+ self._icmp_match(rule, protocol, icmp_code, icmp_type) or
+ self._egress_all_match(rule, protocol, fw_type)
+ )
+
+ if type_match and protocol_match:
+ self.firewall_rule = rule
+ break
+ return self.firewall_rule
+
+ def _tcp_udp_match(self, rule, protocol, start_port, end_port):
+ return (
+ protocol in ['tcp', 'udp'] and
+ protocol == rule['protocol'] and
+ start_port == int(rule['startport']) and
+ end_port == int(rule['endport'])
+ )
+
+ def _egress_all_match(self, rule, protocol, fw_type):
+ return (
+ protocol in ['all'] and
+ protocol == rule['protocol'] and
+ fw_type == 'egress'
+ )
+
+ def _icmp_match(self, rule, protocol, icmp_code, icmp_type):
+ return (
+ protocol == 'icmp' and
+ protocol == rule['protocol'] and
+ icmp_code == rule['icmpcode'] and
+ icmp_type == rule['icmptype']
+ )
+
+ def _type_cidrs_match(self, rule, cidrs, egress_cidrs):
+ if egress_cidrs is not None:
+ return ",".join(egress_cidrs) == rule['cidrlist'] or ",".join(cidrs) == rule['cidrlist']
+ else:
+ return ",".join(cidrs) == rule['cidrlist']
+
+ def create_firewall_rule(self):
+ firewall_rule = self.get_firewall_rule()
+ if not firewall_rule:
+ self.result['changed'] = True
+
+ args = {
+ 'cidrlist': self.module.params.get('cidrs'),
+ 'protocol': self.module.params.get('protocol'),
+ 'startport': self.module.params.get('start_port'),
+ 'endport': self.get_or_fallback('end_port', 'start_port'),
+ 'icmptype': self.module.params.get('icmp_type'),
+ 'icmpcode': self.module.params.get('icmp_code')
+ }
+
+ fw_type = self.module.params.get('type')
+ if not self.module.check_mode:
+ if fw_type == 'egress':
+ args['networkid'] = self.get_network(key='id')
+ res = self.query_api('createEgressFirewallRule', **args)
+ else:
+ args['ipaddressid'] = self.get_ip_address('id')
+ res = self.query_api('createFirewallRule', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ firewall_rule = self.poll_job(res, 'firewallrule')
+
+ if firewall_rule:
+ firewall_rule = self.ensure_tags(resource=firewall_rule, resource_type='Firewallrule')
+ self.firewall_rule = firewall_rule
+
+ return firewall_rule
+
+ def remove_firewall_rule(self):
+ firewall_rule = self.get_firewall_rule()
+ if firewall_rule:
+ self.result['changed'] = True
+
+ args = {
+ 'id': firewall_rule['id']
+ }
+
+ fw_type = self.module.params.get('type')
+ if not self.module.check_mode:
+ if fw_type == 'egress':
+ res = self.query_api('deleteEgressFirewallRule', **args)
+ else:
+ res = self.query_api('deleteFirewallRule', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'firewallrule')
+ return firewall_rule
+
+ def get_result(self, firewall_rule):
+ super(AnsibleCloudStackFirewall, self).get_result(firewall_rule)
+ if firewall_rule:
+ self.result['type'] = self.module.params.get('type')
+ if self.result['type'] == 'egress':
+ self.result['network'] = self.get_network(key='displaytext')
+ if 'cidrlist' in firewall_rule:
+ self.result['cidrs'] = firewall_rule['cidrlist'].split(',') or [firewall_rule['cidrlist']]
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ ip_address=dict(),
+ network=dict(),
+ cidrs=dict(type='list', elements='str', default='0.0.0.0/0', aliases=['cidr']),
+ protocol=dict(choices=['tcp', 'udp', 'icmp', 'all'], default='tcp'),
+ type=dict(choices=['ingress', 'egress'], default='ingress'),
+ icmp_type=dict(type='int'),
+ icmp_code=dict(type='int'),
+ start_port=dict(type='int', aliases=['port']),
+ end_port=dict(type='int'),
+ state=dict(choices=['present', 'absent'], default='present'),
+ zone=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ poll_async=dict(type='bool', default=True),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ ))
+
+ required_together = cs_required_together()
+ required_together.extend([
+ ['icmp_type', 'icmp_code'],
+ ])
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=required_together,
+ required_one_of=(
+ ['ip_address', 'network'],
+ ),
+ mutually_exclusive=(
+ ['icmp_type', 'start_port'],
+ ['icmp_type', 'end_port'],
+ ['ip_address', 'network'],
+ ),
+ supports_check_mode=True
+ )
+
+ acs_fw = AnsibleCloudStackFirewall(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ fw_rule = acs_fw.remove_firewall_rule()
+ else:
+ fw_rule = acs_fw.create_firewall_rule()
+
+ result = acs_fw.get_result(fw_rule)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_host.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_host.py
new file mode 100644
index 00000000..111b4e0e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_host.py
@@ -0,0 +1,607 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_host
+short_description: Manages hosts on Apache CloudStack based clouds.
+description:
+ - Create, update and remove hosts.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the host.
+ type: str
+ required: true
+ aliases: [ ip_address ]
+ url:
+ description:
+ - Url of the host used to create a host.
+ - If not provided, C(http://) and param I(name) is used as url.
+ - Only considered if I(state=present) and host does not yet exist.
+ type: str
+ username:
+ description:
+ - Username for the host.
+ - Required if I(state=present) and host does not yet exist.
+ type: str
+ password:
+ description:
+ - Password for the host.
+ - Required if I(state=present) and host does not yet exist.
+ type: str
+ pod:
+ description:
+ - Name of the pod.
+ - Required if I(state=present) and host does not yet exist.
+ type: str
+ cluster:
+ description:
+ - Name of the cluster.
+ type: str
+ hypervisor:
+ description:
+ - Name of the cluster.
+ - Required if I(state=present) and host does not yet exist.
+ - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator).
+ type: str
+ allocation_state:
+ description:
+ - Allocation state of the host.
+ type: str
+ choices: [ enabled, disabled, maintenance ]
+ host_tags:
+ description:
+ - Tags of the host.
+ type: list
+ elements: str
+ aliases: [ host_tag ]
+ state:
+ description:
+ - State of the host.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ zone:
+ description:
+ - Name of the zone in which the host should be deployed.
+ - If not set, default zone is used.
+ type: str
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Ensure a host is present but disabled
+ ngine_io.cloudstack.cs_host:
+ name: pod01.zone01.example.com
+ cluster: vcenter.example.com/zone01/cluster01
+ pod: pod01
+ zone: zone01
+ hypervisor: VMware
+ allocation_state: disabled
+ host_tags:
+ - perf
+ - gpu
+
+- name: Ensure an existing host is disabled
+ ngine_io.cloudstack.cs_host:
+ name: pod01.zone01.example.com
+ zone: zone01
+ allocation_state: disabled
+
+- name: Ensure an existing host is enabled
+ ngine_io.cloudstack.cs_host:
+ name: pod01.zone01.example.com
+ zone: zone01
+ allocation_state: enabled
+
+- name: Ensure a host is absent
+ ngine_io.cloudstack.cs_host:
+ name: pod01.zone01.example.com
+ zone: zone01
+ state: absent
+'''
+
+RETURN = '''
+---
+capabilities:
+ description: Capabilities of the host.
+ returned: success
+ type: str
+ sample: hvm
+cluster:
+ description: Cluster of the host.
+ returned: success
+ type: str
+ sample: vcenter.example.com/zone/cluster01
+cluster_type:
+ description: Type of the cluster of the host.
+ returned: success
+ type: str
+ sample: ExternalManaged
+cpu_allocated:
+ description: Amount in percent of the host's CPU currently allocated.
+ returned: success
+ type: str
+ sample: 166.25%
+cpu_number:
+ description: Number of CPUs of the host.
+ returned: success
+ type: str
+ sample: 24
+cpu_sockets:
+ description: Number of CPU sockets of the host.
+ returned: success
+ type: int
+ sample: 2
+cpu_speed:
+ description: CPU speed in Mhz
+ returned: success
+ type: int
+ sample: 1999
+cpu_used:
+ description: Amount of the host's CPU currently used.
+ returned: success
+ type: str
+ sample: 33.6%
+cpu_with_overprovisioning:
+ description: Amount of the host's CPU after applying the cpu.overprovisioning.factor.
+ returned: success
+ type: str
+ sample: 959520.0
+created:
+ description: Date when the host was created.
+ returned: success
+ type: str
+ sample: 2015-05-03T15:05:51+0200
+disconnected:
+ description: Date when the host was disconnected.
+ returned: success
+ type: str
+ sample: 2015-05-03T15:05:51+0200
+disk_size_allocated:
+ description: Host's currently allocated disk size.
+ returned: success
+ type: int
+ sample: 2593
+disk_size_total:
+ description: Total disk size of the host
+ returned: success
+ type: int
+ sample: 259300
+events:
+ description: Events available for the host
+ returned: success
+ type: str
+ sample: "Ping; HostDown; AgentConnected; AgentDisconnected; PingTimeout; ShutdownRequested; Remove; StartAgentRebalance; ManagementServerDown"
+ha_host:
+ description: Whether the host is a HA host.
+ returned: success
+ type: bool
+ sample: false
+has_enough_capacity:
+ description: Whether the host has enough CPU and RAM capacity to migrate a VM to it.
+ returned: success
+ type: bool
+ sample: true
+host_tags:
+ description: Comma-separated list of tags for the host.
+ returned: success
+ type: str
+ sample: "perf"
+hypervisor:
+ description: Host's hypervisor.
+ returned: success
+ type: str
+ sample: VMware
+hypervisor_version:
+ description: Hypervisor version.
+ returned: success
+ type: str
+ sample: 5.1
+ip_address:
+ description: IP address of the host
+ returned: success
+ type: str
+ sample: 10.10.10.1
+is_local_storage_active:
+ description: Whether the local storage is available or not.
+ returned: success
+ type: bool
+ sample: false
+last_pinged:
+ description: Date and time the host was last pinged.
+ returned: success
+ type: str
+ sample: "1970-01-17T17:27:32+0100"
+management_server_id:
+ description: Management server ID of the host.
+ returned: success
+ type: int
+ sample: 345050593418
+memory_allocated:
+ description: Amount of the host's memory currently allocated.
+ returned: success
+ type: int
+ sample: 69793218560
+memory_total:
+ description: Total of memory of the host.
+ returned: success
+ type: int
+ sample: 206085263360
+memory_used:
+ description: Amount of the host's memory currently used.
+ returned: success
+ type: int
+ sample: 65504776192
+name:
+ description: Name of the host.
+ returned: success
+ type: str
+ sample: esx32.example.com
+network_kbs_read:
+ description: Incoming network traffic on the host.
+ returned: success
+ type: int
+ sample: 0
+network_kbs_write:
+ description: Outgoing network traffic on the host.
+ returned: success
+ type: int
+ sample: 0
+os_category:
+ description: OS category name of the host.
+ returned: success
+ type: str
+ sample: ...
+out_of_band_management:
+ description: Host out-of-band management information.
+ returned: success
+ type: str
+ sample: ...
+pod:
+ description: Pod name of the host.
+ returned: success
+ type: str
+ sample: Pod01
+removed:
+ description: Date and time the host was removed.
+ returned: success
+ type: str
+ sample: "1970-01-17T17:27:32+0100"
+resource_state:
+ description: Resource state of the host.
+ returned: success
+ type: str
+ sample: Enabled
+allocation_state::
+ description: Allocation state of the host.
+ returned: success
+ type: str
+ sample: enabled
+state:
+ description: State of the host.
+ returned: success
+ type: str
+ sample: Up
+suitable_for_migration:
+ description: Whether this host is suitable (has enough capacity and satisfies all conditions like hosttags, max guests VM limit, etc) to migrate a VM
+ to it or not.
+ returned: success
+ type: str
+ sample: true
+host_type:
+ description: Type of the host.
+ returned: success
+ type: str
+ sample: Routing
+host_version:
+ description: Version of the host.
+ returned: success
+ type: str
+ sample: 4.5.2
+gpu_group:
+ description: GPU cards present in the host.
+ returned: success
+ type: list
+ sample: []
+zone:
+ description: Zone of the host.
+ returned: success
+ type: str
+ sample: zone01
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+import time
+
+
+class AnsibleCloudStackHost(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackHost, self).__init__(module)
+ self.returns = {
+ 'averageload': 'average_load',
+ 'capabilities': 'capabilities',
+ 'clustername': 'cluster',
+ 'clustertype': 'cluster_type',
+ 'cpuallocated': 'cpu_allocated',
+ 'cpunumber': 'cpu_number',
+ 'cpusockets': 'cpu_sockets',
+ 'cpuspeed': 'cpu_speed',
+ 'cpuused': 'cpu_used',
+ 'cpuwithoverprovisioning': 'cpu_with_overprovisioning',
+ 'disconnected': 'disconnected',
+ 'details': 'details',
+ 'disksizeallocated': 'disk_size_allocated',
+ 'disksizetotal': 'disk_size_total',
+ 'events': 'events',
+ 'hahost': 'ha_host',
+ 'hasenoughcapacity': 'has_enough_capacity',
+ 'hypervisor': 'hypervisor',
+ 'hypervisorversion': 'hypervisor_version',
+ 'ipaddress': 'ip_address',
+ 'islocalstorageactive': 'is_local_storage_active',
+ 'lastpinged': 'last_pinged',
+ 'managementserverid': 'management_server_id',
+ 'memoryallocated': 'memory_allocated',
+ 'memorytotal': 'memory_total',
+ 'memoryused': 'memory_used',
+ 'networkkbsread': 'network_kbs_read',
+ 'networkkbswrite': 'network_kbs_write',
+ 'oscategoryname': 'os_category',
+ 'outofbandmanagement': 'out_of_band_management',
+ 'podname': 'pod',
+ 'removed': 'removed',
+ 'resourcestate': 'resource_state',
+ 'suitableformigration': 'suitable_for_migration',
+ 'type': 'host_type',
+ 'version': 'host_version',
+ 'gpugroup': 'gpu_group',
+ }
+ # States only usable by the updateHost API
+ self.allocation_states_for_update = {
+ 'enabled': 'Enable',
+ 'disabled': 'Disable',
+ }
+ self.host = None
+
+ def get_cluster(self, key=None):
+ cluster_name = self.module.params.get('cluster')
+ if not cluster_name:
+ return None
+ args = {
+ 'name': cluster_name,
+ 'zoneid': self.get_zone(key='id'),
+ }
+ clusters = self.query_api('listClusters', **args)
+ if clusters:
+ return self._get_by_key(key, clusters['cluster'][0])
+ self.module.fail_json(msg="Cluster %s not found" % cluster_name)
+
+ def get_host_tags(self):
+ host_tags = self.module.params.get('host_tags')
+ if host_tags is None:
+ return None
+ return ','.join(host_tags)
+
+ def get_host(self, refresh=False):
+ if self.host is not None and not refresh:
+ return self.host
+
+ name = self.module.params.get('name')
+ args = {
+ 'zoneid': self.get_zone(key='id'),
+ 'fetch_list': True,
+ }
+ res = self.query_api('listHosts', **args)
+ if res:
+ for h in res:
+ if name in [h['ipaddress'], h['name']]:
+ self.host = h
+ return self.host
+
+ def _handle_allocation_state(self, host):
+ allocation_state = self.module.params.get('allocation_state')
+ if not allocation_state:
+ return host
+
+ host = self._set_host_allocation_state(host)
+
+ # In case host in maintenance and target is maintenance
+ if host['allocationstate'].lower() == allocation_state and allocation_state == 'maintenance':
+ return host
+
+ # Cancel maintenance if target state is enabled/disabled
+ elif allocation_state in list(self.allocation_states_for_update.keys()):
+ host = self.disable_maintenance(host)
+ host = self._update_host(host, self.allocation_states_for_update[allocation_state])
+
+ # Only an enabled host can put in maintenance
+ elif allocation_state == 'maintenance':
+ host = self._update_host(host, 'Enable')
+ host = self.enable_maintenance(host)
+
+ return host
+
+ def _set_host_allocation_state(self, host):
+ if host is None:
+ host['allocationstate'] = 'Enable'
+
+ # Set host allocationstate to be disabled/enabled
+ elif host['resourcestate'].lower() in list(self.allocation_states_for_update.keys()):
+ host['allocationstate'] = self.allocation_states_for_update[host['resourcestate'].lower()]
+
+ else:
+ host['allocationstate'] = host['resourcestate']
+
+ return host
+
+ def present_host(self):
+ host = self.get_host()
+
+ if not host:
+ host = self._create_host(host)
+ else:
+ host = self._update_host(host)
+
+ if host:
+ host = self._handle_allocation_state(host)
+
+ return host
+
+ def _get_url(self):
+ url = self.module.params.get('url')
+ if url:
+ return url
+ else:
+ return "http://%s" % self.module.params.get('name')
+
+ def _create_host(self, host):
+ required_params = [
+ 'password',
+ 'username',
+ 'hypervisor',
+ 'pod',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+ self.result['changed'] = True
+ args = {
+ 'hypervisor': self.module.params.get('hypervisor'),
+ 'url': self._get_url(),
+ 'username': self.module.params.get('username'),
+ 'password': self.module.params.get('password'),
+ 'podid': self.get_pod(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'clusterid': self.get_cluster(key='id'),
+ 'hosttags': self.get_host_tags(),
+ }
+ if not self.module.check_mode:
+ host = self.query_api('addHost', **args)
+ host = host['host'][0]
+ return host
+
+ def _update_host(self, host, allocation_state=None):
+ args = {
+ 'id': host['id'],
+ 'hosttags': self.get_host_tags(),
+ 'allocationstate': allocation_state,
+ }
+
+ if allocation_state is not None:
+ host = self._set_host_allocation_state(host)
+
+ if self.has_changed(args, host):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ host = self.query_api('updateHost', **args)
+ host = host['host']
+
+ return host
+
+ def absent_host(self):
+ host = self.get_host()
+ if host:
+ self.result['changed'] = True
+ args = {
+ 'id': host['id'],
+ }
+ if not self.module.check_mode:
+ res = self.enable_maintenance(host)
+ if res:
+ res = self.query_api('deleteHost', **args)
+ return host
+
+ def enable_maintenance(self, host):
+ if host['resourcestate'] not in ['PrepareForMaintenance', 'Maintenance']:
+ self.result['changed'] = True
+ args = {
+ 'id': host['id'],
+ }
+ if not self.module.check_mode:
+ res = self.query_api('prepareHostForMaintenance', **args)
+ self.poll_job(res, 'host')
+ host = self._poll_for_maintenance()
+ return host
+
+ def disable_maintenance(self, host):
+ if host['resourcestate'] in ['PrepareForMaintenance', 'Maintenance']:
+ self.result['changed'] = True
+ args = {
+ 'id': host['id'],
+ }
+ if not self.module.check_mode:
+ res = self.query_api('cancelHostMaintenance', **args)
+ host = self.poll_job(res, 'host')
+ return host
+
+ def _poll_for_maintenance(self):
+ for i in range(0, 300):
+ time.sleep(2)
+ host = self.get_host(refresh=True)
+ if not host:
+ return None
+ elif host['resourcestate'] != 'PrepareForMaintenance':
+ return host
+ self.fail_json(msg="Polling for maintenance timed out")
+
+ def get_result(self, host):
+ super(AnsibleCloudStackHost, self).get_result(host)
+ if host:
+ self.result['allocation_state'] = host['resourcestate'].lower()
+ self.result['host_tags'] = host['hosttags'].split(',') if host.get('hosttags') else []
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True, aliases=['ip_address']),
+ url=dict(),
+ password=dict(no_log=True),
+ username=dict(),
+ hypervisor=dict(),
+ allocation_state=dict(choices=['enabled', 'disabled', 'maintenance']),
+ pod=dict(),
+ cluster=dict(),
+ host_tags=dict(type='list', elements='str', aliases=['host_tag']),
+ zone=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_host = AnsibleCloudStackHost(module)
+
+ state = module.params.get('state')
+ if state == 'absent':
+ host = acs_host.absent_host()
+ else:
+ host = acs_host.present_host()
+
+ result = acs_host.get_result(host)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_image_store.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_image_store.py
new file mode 100644
index 00000000..b97d6e26
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_image_store.py
@@ -0,0 +1,246 @@
+#!/usr/bin/python
+
+# Copyright: (c) 2019, Patryk Cichy @PatTheSilent
+# 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: cs_image_store
+
+short_description: Manages CloudStack Image Stores.
+
+
+description:
+ - Deploy, remove, recreate CloudStack Image Stores.
+
+version_added: 0.1.0
+options:
+ url:
+ description:
+ - The URL for the Image Store.
+ - Required when I(state=present).
+ type: str
+ name:
+ description:
+ - The ID of the Image Store. Required when deleting a Image Store.
+ required: true
+ type: str
+ zone:
+ description:
+ - The Zone name for the Image Store.
+ required: true
+ type: str
+ state:
+ description:
+ - Stage of the Image Store
+ choices: [present, absent]
+ default: present
+ type: str
+ provider:
+ description:
+ - The image store provider name. Required when creating a new Image Store
+ type: str
+ force_recreate:
+ description:
+ - Set to C(yes) if you're changing an existing Image Store.
+ - This will force the recreation of the Image Store.
+ - Recreation might fail if there are snapshots present on the Image Store. Delete them before running the recreation.
+ type: bool
+ default: no
+
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+
+
+author:
+ - Patryk Cichy (@PatTheSilent)
+'''
+
+EXAMPLES = '''
+- name: Add a Image Store (NFS)
+ ngine_io.cloudstack.cs_image_store:
+ zone: zone-01
+ name: nfs-01
+ provider: NFS
+ url: nfs://192.168.21.16/exports/secondary
+
+
+# Change the NFS share URL and force a Image Store recreation
+- name: Change the NFS url
+ ngine_io.cloudstack.cs_image_store:
+ zone: zone-01
+ name: nfs-01
+ provider: NFS
+ force_recreate: yes
+ url: nfs://192.168.21.10/shares/secondary
+
+- name: delete the image store
+ ngine_io.cloudstack.cs_image_store:
+ name: nfs-01
+ zone: zone-01
+ state: absent
+
+'''
+
+RETURN = '''
+id:
+ description: the ID of the image store
+ type: str
+ returned: success
+ sample: feb11a84-a093-45eb-b84d-7f680313c40b
+name:
+ description: the name of the image store
+ type: str
+ returned: success
+ sample: nfs-01
+protocol:
+ description: the protocol of the image store
+ type: str
+ returned: success
+ sample: nfs
+provider_name:
+ description: the provider name of the image store
+ type: str
+ returned: success
+ sample: NFS
+scope:
+ description: the scope of the image store
+ type: str
+ returned: success
+ sample: ZONE
+url:
+ description: the url of the image store
+ type: str
+ sample: nfs://192.168.21.16/exports/secondary
+ returned: success
+zone:
+ description: the Zone name of the image store
+ type: str
+ returned: success
+ sample: zone-01
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together
+
+
+class AnsibleCloudstackImageStore(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudstackImageStore, self).__init__(module)
+ self.returns = {
+ 'protocol': 'protocol',
+ 'providername': 'provider_name',
+ 'scope': 'scope',
+ 'url': 'url'
+ }
+ self.image_store = None
+
+ def get_storage_providers(self, storage_type="image"):
+ args = {
+ 'type': storage_type
+ }
+ storage_provides = self.query_api('listStorageProviders', **args)
+ return [provider.get('name') for provider in storage_provides.get('dataStoreProvider')]
+
+ def get_image_store(self):
+ if self.image_store:
+ return self.image_store
+ image_store = self.module.params.get('name')
+ args = {
+ 'name': self.module.params.get('name'),
+ 'zoneid': self.get_zone(key='id')
+ }
+
+ image_stores = self.query_api('listImageStores', **args)
+ if image_stores:
+ for img_s in image_stores.get('imagestore'):
+ if image_store.lower() in [img_s['name'].lower(), img_s['id']]:
+ self.image_store = img_s
+ break
+
+ return self.image_store
+
+ def present_image_store(self):
+ provider_list = self.get_storage_providers()
+ image_store = self.get_image_store()
+
+ if self.module.params.get('provider') not in provider_list:
+ self.module.fail_json(
+ msg='Provider %s is not in the provider list (%s). Please specify a correct provider' % (
+ self.module.params.get('provider'), provider_list))
+ args = {
+ 'name': self.module.params.get('name'),
+ 'url': self.module.params.get('url'),
+ 'zoneid': self.get_zone(key='id'),
+ 'provider': self.module.params.get('provider')
+ }
+ if not image_store:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('addImageStore', **args)
+ self.image_store = res.get('imagestore')
+ else:
+ # Cloudstack API expects 'provider' but returns 'providername'
+ args['providername'] = args.pop('provider')
+ if self.has_changed(args, image_store):
+ if self.module.params.get('force_recreate'):
+ self.absent_image_store()
+ self.image_store = None
+ self.image_store = self.present_image_store()
+ else:
+ self.module.warn("Changes to the Image Store won't be applied"
+ "Use force_recreate=yes to allow the store to be recreated")
+
+ return self.image_store
+
+ def absent_image_store(self):
+ image_store = self.get_image_store()
+ if image_store:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ args = {
+ 'id': image_store.get('id')
+ }
+ self.query_api('deleteImageStore', **args)
+ return image_store
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ url=dict(),
+ name=dict(required=True),
+ zone=dict(required=True),
+ provider=dict(),
+ force_recreate=dict(type='bool', default=False),
+ state=dict(choices=['present', 'absent'], default='present'),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ required_if=[
+ ('state', 'present', ['url', 'provider']),
+ ],
+ supports_check_mode=True
+ )
+
+ acis_do = AnsibleCloudstackImageStore(module)
+
+ state = module.params.get('state')
+ if state == "absent":
+ image_store = acis_do.absent_image_store()
+ else:
+ image_store = acis_do.present_image_store()
+
+ result = acis_do.get_result(image_store)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance.py
new file mode 100644
index 00000000..97a0ef93
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance.py
@@ -0,0 +1,1101 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_instance
+short_description: Manages instances and virtual machines on Apache CloudStack based clouds.
+description:
+ - Deploy, start, update, scale, restart, restore, stop and destroy instances.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Host name of the instance. C(name) can only contain ASCII letters.
+ - Name will be generated (UUID) by CloudStack if not specified and can not be changed afterwards.
+ - Either C(name) or C(display_name) is required.
+ type: str
+ display_name:
+ description:
+ - Custom display name of the instances.
+ - Display name will be set to I(name) if not specified.
+ - Either I(name) or I(display_name) is required.
+ type: str
+ group:
+ description:
+ - Group in where the new instance should be in.
+ type: str
+ state:
+ description:
+ - State of the instance.
+ type: str
+ default: present
+ choices: [ deployed, started, stopped, restarted, restored, destroyed, expunged, present, absent ]
+ service_offering:
+ description:
+ - Name or id of the service offering of the new instance.
+ - If not set, first found service offering is used.
+ type: str
+ cpu:
+ description:
+ - The number of CPUs to allocate to the instance, used with custom service offerings
+ type: int
+ cpu_speed:
+ description:
+ - The clock speed/shares allocated to the instance, used with custom service offerings
+ type: int
+ memory:
+ description:
+ - The memory allocated to the instance, used with custom service offerings
+ type: int
+ template:
+ description:
+ - Name, display text or id of the template to be used for creating the new instance.
+ - Required when using I(state=present).
+ - Mutually exclusive with I(iso) option.
+ type: str
+ iso:
+ description:
+ - Name or id of the ISO to be used for creating the new instance.
+ - Required when using I(state=present).
+ - Mutually exclusive with I(template) option.
+ type: str
+ template_filter:
+ description:
+ - Name of the filter used to search for the template or iso.
+ - Used for params I(iso) or I(template) on I(state=present).
+ - The filter C(all) was added in 2.6.
+ type: str
+ default: executable
+ choices: [ all, featured, self, selfexecutable, sharedexecutable, executable, community ]
+ aliases: [ iso_filter ]
+ hypervisor:
+ description:
+ - Name the hypervisor to be used for creating the new instance.
+ - Relevant when using I(state=present), but only considered if not set on ISO/template.
+ - If not set or found on ISO/template, first found hypervisor will be used.
+ - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator).
+ type: str
+ keyboard:
+ description:
+ - Keyboard device type for the instance.
+ type: str
+ choices: [ 'de', 'de-ch', 'es', 'fi', 'fr', 'fr-be', 'fr-ch', 'is', 'it', 'jp', 'nl-be', 'no', 'pt', 'uk', 'us' ]
+ networks:
+ description:
+ - List of networks to use for the new instance.
+ type: list
+ elements: str
+ aliases: [ network ]
+ ip_address:
+ description:
+ - IPv4 address for default instance's network during creation.
+ type: str
+ ip6_address:
+ description:
+ - IPv6 address for default instance's network.
+ type: str
+ ip_to_networks:
+ description:
+ - "List of mappings in the form I({'network': NetworkName, 'ip': 1.2.3.4})"
+ - Mutually exclusive with I(networks) option.
+ type: list
+ elements: dict
+ aliases: [ ip_to_network ]
+ disk_offering:
+ description:
+ - Name of the disk offering to be used.
+ type: str
+ disk_size:
+ description:
+ - Disk size in GByte required if deploying instance from ISO.
+ type: int
+ root_disk_size:
+ description:
+ - Root disk size in GByte required if deploying instance with KVM hypervisor and want resize the root disk size at startup
+ (need CloudStack >= 4.4, cloud-initramfs-growroot installed and enabled in the template)
+ type: int
+ security_groups:
+ description:
+ - List of security groups the instance to be applied to.
+ type: list
+ elements: str
+ aliases: [ security_group ]
+ host:
+ description:
+ - Host on which an instance should be deployed or started on.
+ - Only considered when I(state=started) or instance is running.
+ - Requires root admin privileges.
+ type: str
+ domain:
+ description:
+ - Domain the instance is related to.
+ type: str
+ account:
+ description:
+ - Account the instance is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the instance to be deployed in.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the instance should be deployed.
+ - If not set, default zone is used.
+ type: str
+ ssh_key:
+ description:
+ - Name of the SSH key to be deployed on the new instance.
+ type: str
+ affinity_groups:
+ description:
+ - Affinity groups names to be applied to the new instance.
+ type: list
+ elements: str
+ aliases: [ affinity_group ]
+ user_data:
+ description:
+ - Optional data (ASCII) that can be sent to the instance upon a successful deployment.
+ - The data will be automatically base64 encoded.
+ - Consider switching to HTTP_POST by using I(CLOUDSTACK_METHOD=post) to increase the HTTP_GET size limit of 2KB to 32 KB.
+ type: str
+ force:
+ description:
+ - Force stop/start the instance if required to apply changes, otherwise a running instance will not be changed.
+ type: bool
+ default: no
+ allow_root_disk_shrink:
+ description:
+ - Enables a volume shrinkage when the new size is smaller than the old one.
+ type: bool
+ default: no
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys C(key) and C(value).
+ - "If you want to delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+ details:
+ description:
+ - Map to specify custom parameters.
+ type: dict
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+# NOTE: Names of offerings and ISOs depending on the CloudStack configuration.
+- name: create a instance from an ISO
+ ngine_io.cloudstack.cs_instance:
+ name: web-vm-1
+ iso: Linux Debian 7 64-bit
+ hypervisor: VMware
+ project: Integration
+ zone: ch-zrh-ix-01
+ service_offering: 1cpu_1gb
+ disk_offering: PerfPlus Storage
+ disk_size: 20
+ networks:
+ - Server Integration
+ - Sync Integration
+ - Storage Integration
+
+- name: for changing a running instance, use the 'force' parameter
+ ngine_io.cloudstack.cs_instance:
+ name: web-vm-1
+ display_name: web-vm-01.example.com
+ iso: Linux Debian 7 64-bit
+ service_offering: 2cpu_2gb
+ force: yes
+
+# NOTE: user_data can be used to kickstart the instance using cloud-init yaml config.
+- name: create or update a instance on Exoscale's public cloud using display_name.
+ ngine_io.cloudstack.cs_instance:
+ display_name: web-vm-1
+ template: Linux Debian 7 64-bit
+ service_offering: Tiny
+ ssh_key: john@example.com
+ tags:
+ - key: admin
+ value: john
+ - key: foo
+ value: bar
+ user_data: |
+ #cloud-config
+ packages:
+ - nginx
+
+- name: create an instance with multiple interfaces specifying the IP addresses
+ ngine_io.cloudstack.cs_instance:
+ name: web-vm-1
+ template: Linux Debian 7 64-bit
+ service_offering: Tiny
+ ip_to_networks:
+ - network: NetworkA
+ ip: 10.1.1.1
+ - network: NetworkB
+ ip: 192.0.2.1
+
+- name: ensure an instance is stopped
+ ngine_io.cloudstack.cs_instance:
+ name: web-vm-1
+ state: stopped
+
+- name: ensure an instance is running
+ ngine_io.cloudstack.cs_instance:
+ name: web-vm-1
+ state: started
+
+- name: remove an instance
+ ngine_io.cloudstack.cs_instance:
+ name: web-vm-1
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the instance.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: Name of the instance.
+ returned: success
+ type: str
+ sample: web-01
+display_name:
+ description: Display name of the instance.
+ returned: success
+ type: str
+ sample: web-01
+group:
+ description: Group name of the instance is related.
+ returned: success
+ type: str
+ sample: web
+created:
+ description: Date of the instance was created.
+ returned: success
+ type: str
+ sample: 2014-12-01T14:57:57+0100
+password_enabled:
+ description: True if password setting is enabled.
+ returned: success
+ type: bool
+ sample: true
+password:
+ description: The password of the instance if exists.
+ returned: if available
+ type: str
+ sample: Ge2oe7Do
+ssh_key:
+ description: Name of SSH key deployed to instance.
+ returned: if available
+ type: str
+ sample: key@work
+domain:
+ description: Domain the instance is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the instance is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project the instance is related to.
+ returned: success
+ type: str
+ sample: Production
+default_ip:
+ description: Default IP address of the instance.
+ returned: success
+ type: str
+ sample: 10.23.37.42
+default_ip6:
+ description: Default IPv6 address of the instance.
+ returned: if available
+ type: str
+ sample: 2a04:c43:c00:a07:4b4:beff:fe00:74
+public_ip:
+ description: Public IP address with instance via static NAT rule.
+ returned: if available
+ type: str
+ sample: 1.2.3.4
+iso:
+ description: Name of ISO the instance was deployed with.
+ returned: if available
+ type: str
+ sample: Debian-8-64bit
+template:
+ description: Name of template the instance was deployed with.
+ returned: success
+ type: str
+ sample: Linux Debian 9 64-bit
+template_display_text:
+ description: Display text of template the instance was deployed with.
+ returned: success
+ type: str
+ sample: Linux Debian 9 64-bit 200G Disk (2017-10-08-622866)
+service_offering:
+ description: Name of the service offering the instance has.
+ returned: success
+ type: str
+ sample: 2cpu_2gb
+zone:
+ description: Name of zone the instance is in.
+ returned: success
+ type: str
+ sample: ch-gva-2
+state:
+ description: State of the instance.
+ returned: success
+ type: str
+ sample: Running
+security_groups:
+ description: Security groups the instance is in.
+ returned: success
+ type: list
+ sample: '[ "default" ]'
+affinity_groups:
+ description: Affinity groups the instance is in.
+ returned: success
+ type: list
+ sample: '[ "webservers" ]'
+tags:
+ description: List of resource tags associated with the instance.
+ returned: success
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+hypervisor:
+ description: Hypervisor related to this instance.
+ returned: success
+ type: str
+ sample: KVM
+host:
+ description: Hostname of hypervisor an instance is running on.
+ returned: success and instance is running
+ type: str
+ sample: host-01.example.com
+instance_name:
+ description: Internal name of the instance (ROOT admin only).
+ returned: success
+ type: str
+ sample: i-44-3992-VM
+user-data:
+ description: Optional data sent to the instance.
+ returned: success
+ type: str
+ sample: VXNlciBkYXRhIGV4YW1wbGUK
+'''
+
+import base64
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils._text import to_bytes, to_text
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackInstance(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackInstance, self).__init__(module)
+ self.returns = {
+ 'group': 'group',
+ 'hypervisor': 'hypervisor',
+ 'instancename': 'instance_name',
+ 'publicip': 'public_ip',
+ 'passwordenabled': 'password_enabled',
+ 'password': 'password',
+ 'serviceofferingname': 'service_offering',
+ 'isoname': 'iso',
+ 'templatename': 'template',
+ 'templatedisplaytext': 'template_display_text',
+ 'keypair': 'ssh_key',
+ 'hostname': 'host',
+ }
+ self.instance = None
+ self.template = None
+ self.iso = None
+
+ def get_service_offering_id(self):
+ service_offering = self.module.params.get('service_offering')
+
+ service_offerings = self.query_api('listServiceOfferings')
+ if service_offerings:
+ if not service_offering:
+ return service_offerings['serviceoffering'][0]['id']
+
+ for s in service_offerings['serviceoffering']:
+ if service_offering in [s['name'], s['id']]:
+ return s['id']
+ self.fail_json(msg="Service offering '%s' not found" % service_offering)
+
+ def get_host_id(self):
+ host_name = self.module.params.get('host')
+ if not host_name:
+ return None
+
+ args = {
+ 'type': 'routing',
+ 'zoneid': self.get_zone(key='id'),
+ }
+ hosts = self.query_api('listHosts', **args)
+ if hosts:
+ for h in hosts['host']:
+ if h['name'] == host_name:
+ return h['id']
+
+ self.fail_json(msg="Host '%s' not found" % host_name)
+
+ def get_template_or_iso(self, key=None):
+ template = self.module.params.get('template')
+ iso = self.module.params.get('iso')
+
+ if not template and not iso:
+ return None
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'isrecursive': True,
+ 'fetch_list': True,
+ }
+
+ if template:
+ if self.template:
+ return self._get_by_key(key, self.template)
+
+ rootdisksize = self.module.params.get('root_disk_size')
+ args['templatefilter'] = self.module.params.get('template_filter')
+ args['fetch_list'] = True
+ templates = self.query_api('listTemplates', **args)
+ if templates:
+ for t in templates:
+ if template in [t.get('displaytext', None), t['name'], t['id']]:
+ if rootdisksize and t['size'] > rootdisksize * 1024 ** 3:
+ continue
+ self.template = t
+ return self._get_by_key(key, self.template)
+
+ if rootdisksize:
+ more_info = " (with size <= %s)" % rootdisksize
+ else:
+ more_info = ""
+
+ self.module.fail_json(msg="Template '%s' not found%s" % (template, more_info))
+
+ elif iso:
+ if self.iso:
+ return self._get_by_key(key, self.iso)
+
+ args['isofilter'] = self.module.params.get('template_filter')
+ args['fetch_list'] = True
+ isos = self.query_api('listIsos', **args)
+ if isos:
+ for i in isos:
+ if iso in [i['displaytext'], i['name'], i['id']]:
+ self.iso = i
+ return self._get_by_key(key, self.iso)
+
+ self.module.fail_json(msg="ISO '%s' not found" % iso)
+
+ def get_instance(self):
+ instance = self.instance
+ if not instance:
+ instance_name = self.get_or_fallback('name', 'display_name')
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'fetch_list': True,
+ }
+ # Do not pass zoneid, as the instance name must be unique across zones.
+ instances = self.query_api('listVirtualMachines', **args)
+ if instances:
+ for v in instances:
+ if instance_name.lower() in [v['name'].lower(), v['displayname'].lower(), v['id']]:
+ self.instance = v
+ break
+ return self.instance
+
+ def _get_instance_user_data(self, instance):
+ # Query the user data if we need to
+ if 'userdata' in instance:
+ return instance['userdata']
+
+ user_data = ""
+ if self.get_user_data() is not None and instance.get('id'):
+ res = self.query_api('getVirtualMachineUserData', virtualmachineid=instance['id'])
+ user_data = res['virtualmachineuserdata'].get('userdata', "")
+ return user_data
+
+ def get_iptonetwork_mappings(self):
+ network_mappings = self.module.params.get('ip_to_networks')
+ if network_mappings is None:
+ return
+
+ if network_mappings and self.module.params.get('networks'):
+ self.module.fail_json(msg="networks and ip_to_networks are mutually exclusive.")
+
+ network_names = [n['network'] for n in network_mappings]
+ ids = self.get_network_ids(network_names)
+ res = []
+ for i, data in enumerate(network_mappings):
+ res.append({'networkid': ids[i], 'ip': data['ip']})
+ return res
+
+ def get_ssh_keypair(self, key=None, name=None, fail_on_missing=True):
+ ssh_key_name = name or self.module.params.get('ssh_key')
+ if ssh_key_name is None:
+ return
+
+ args = {
+ 'domainid': self.get_domain('id'),
+ 'account': self.get_account('name'),
+ 'projectid': self.get_project('id'),
+ 'name': ssh_key_name,
+ }
+ ssh_key_pairs = self.query_api('listSSHKeyPairs', **args)
+ if 'sshkeypair' in ssh_key_pairs:
+ return self._get_by_key(key=key, my_dict=ssh_key_pairs['sshkeypair'][0])
+
+ elif fail_on_missing:
+ self.module.fail_json(msg="SSH key not found: %s" % ssh_key_name)
+
+ def ssh_key_has_changed(self):
+ ssh_key_name = self.module.params.get('ssh_key')
+ if ssh_key_name is None:
+ return False
+
+ # Fails if keypair for param is inexistent
+ param_ssh_key_fp = self.get_ssh_keypair(key='fingerprint')
+
+ # CloudStack 4.5 does return keypair on instance for a non existent key.
+ instance_ssh_key_name = self.instance.get('keypair')
+ if instance_ssh_key_name is None:
+ return True
+
+ # Get fingerprint for keypair of instance but do not fail if inexistent.
+ instance_ssh_key_fp = self.get_ssh_keypair(key='fingerprint', name=instance_ssh_key_name, fail_on_missing=False)
+ if not instance_ssh_key_fp:
+ return True
+
+ # Compare fingerprints to ensure the keypair changed
+ if instance_ssh_key_fp != param_ssh_key_fp:
+ return True
+ return False
+
+ def security_groups_has_changed(self):
+ security_groups = self.module.params.get('security_groups')
+ if security_groups is None:
+ return False
+
+ security_groups = [s.lower() for s in security_groups]
+ instance_security_groups = self.instance.get('securitygroup') or []
+
+ instance_security_group_names = []
+ for instance_security_group in instance_security_groups:
+ if instance_security_group['name'].lower() not in security_groups:
+ return True
+ else:
+ instance_security_group_names.append(instance_security_group['name'].lower())
+
+ for security_group in security_groups:
+ if security_group not in instance_security_group_names:
+ return True
+ return False
+
+ def get_network_ids(self, network_names=None):
+ if network_names is None:
+ network_names = self.module.params.get('networks')
+
+ if not network_names:
+ return None
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'fetch_list': True,
+ }
+ networks = self.query_api('listNetworks', **args)
+ if not networks:
+ self.module.fail_json(msg="No networks available")
+
+ network_ids = []
+ network_displaytexts = []
+ for network_name in network_names:
+ for n in networks:
+ if network_name in [n['displaytext'], n['name'], n['id']]:
+ network_ids.append(n['id'])
+ network_displaytexts.append(n['name'])
+ break
+
+ if len(network_ids) != len(network_names):
+ self.module.fail_json(msg="Could not find all networks, networks list found: %s" % network_displaytexts)
+
+ return network_ids
+
+ def present_instance(self, start_vm=True):
+ instance = self.get_instance()
+
+ if not instance:
+ instance = self.deploy_instance(start_vm=start_vm)
+ else:
+ instance = self.recover_instance(instance=instance)
+ instance = self.update_instance(instance=instance, start_vm=start_vm)
+
+ # In check mode, we do not necessarily have an instance
+ if instance:
+ instance = self.ensure_tags(resource=instance, resource_type='UserVm')
+ # refresh instance data
+ self.instance = instance
+
+ return instance
+
+ def get_user_data(self):
+ user_data = self.module.params.get('user_data')
+ if user_data is not None:
+ user_data = to_text(base64.b64encode(to_bytes(user_data)))
+ return user_data
+
+ def get_details(self):
+ details = self.module.params.get('details')
+ cpu = self.module.params.get('cpu')
+ cpu_speed = self.module.params.get('cpu_speed')
+ memory = self.module.params.get('memory')
+ if all([cpu, cpu_speed, memory]):
+ details.extends({
+ 'cpuNumber': cpu,
+ 'cpuSpeed': cpu_speed,
+ 'memory': memory,
+ })
+
+ return details
+
+ def deploy_instance(self, start_vm=True):
+ self.result['changed'] = True
+ networkids = self.get_network_ids()
+ if networkids is not None:
+ networkids = ','.join(networkids)
+
+ args = {}
+ args['templateid'] = self.get_template_or_iso(key='id')
+ if not args['templateid']:
+ self.module.fail_json(msg="Template or ISO is required.")
+
+ args['zoneid'] = self.get_zone(key='id')
+ args['serviceofferingid'] = self.get_service_offering_id()
+ args['account'] = self.get_account(key='name')
+ args['domainid'] = self.get_domain(key='id')
+ args['projectid'] = self.get_project(key='id')
+ args['diskofferingid'] = self.get_disk_offering(key='id')
+ args['networkids'] = networkids
+ args['iptonetworklist'] = self.get_iptonetwork_mappings()
+ args['userdata'] = self.get_user_data()
+ args['keyboard'] = self.module.params.get('keyboard')
+ args['ipaddress'] = self.module.params.get('ip_address')
+ args['ip6address'] = self.module.params.get('ip6_address')
+ args['name'] = self.module.params.get('name')
+ args['displayname'] = self.get_or_fallback('display_name', 'name')
+ args['group'] = self.module.params.get('group')
+ args['keypair'] = self.get_ssh_keypair(key='name')
+ args['size'] = self.module.params.get('disk_size')
+ args['startvm'] = start_vm
+ args['rootdisksize'] = self.module.params.get('root_disk_size')
+ args['affinitygroupnames'] = self.module.params.get('affinity_groups')
+ args['details'] = self.get_details()
+ args['securitygroupnames'] = self.module.params.get('security_groups')
+ args['hostid'] = self.get_host_id()
+
+ template_iso = self.get_template_or_iso()
+ if 'hypervisor' not in template_iso:
+ args['hypervisor'] = self.get_hypervisor()
+
+ instance = None
+ if not self.module.check_mode:
+ instance = self.query_api('deployVirtualMachine', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ instance = self.poll_job(instance, 'virtualmachine')
+ return instance
+
+ def update_instance(self, instance, start_vm=True):
+ # Service offering data
+ args_service_offering = {
+ 'id': instance['id'],
+ }
+ if self.module.params.get('service_offering'):
+ args_service_offering['serviceofferingid'] = self.get_service_offering_id()
+ service_offering_changed = self.has_changed(args_service_offering, instance)
+
+ # Instance data
+ args_instance_update = {
+ 'id': instance['id'],
+ 'userdata': self.get_user_data(),
+ }
+ instance['userdata'] = self._get_instance_user_data(instance)
+ args_instance_update['ostypeid'] = self.get_os_type(key='id')
+ if self.module.params.get('group'):
+ args_instance_update['group'] = self.module.params.get('group')
+ if self.module.params.get('display_name'):
+ args_instance_update['displayname'] = self.module.params.get('display_name')
+ instance_changed = self.has_changed(args_instance_update, instance)
+
+ ssh_key_changed = self.ssh_key_has_changed()
+
+ security_groups_changed = self.security_groups_has_changed()
+
+ # Volume data
+ args_volume_update = {}
+ root_disk_size = self.module.params.get('root_disk_size')
+ root_disk_size_changed = False
+
+ if root_disk_size is not None:
+ res = self.query_api('listVolumes', type='ROOT', virtualmachineid=instance['id'])
+ [volume] = res['volume']
+
+ size = volume['size'] >> 30
+
+ args_volume_update['id'] = volume['id']
+ args_volume_update['size'] = root_disk_size
+
+ shrinkok = self.module.params.get('allow_root_disk_shrink')
+ if shrinkok:
+ args_volume_update['shrinkok'] = shrinkok
+
+ root_disk_size_changed = root_disk_size != size
+
+ changed = [
+ service_offering_changed,
+ instance_changed,
+ security_groups_changed,
+ ssh_key_changed,
+ root_disk_size_changed,
+ ]
+
+ if any(changed):
+ force = self.module.params.get('force')
+ instance_state = instance['state'].lower()
+ if instance_state == 'stopped' or force:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+
+ # Ensure VM has stopped
+ instance = self.stop_instance()
+ instance = self.poll_job(instance, 'virtualmachine')
+ self.instance = instance
+
+ # Change service offering
+ if service_offering_changed:
+ res = self.query_api('changeServiceForVirtualMachine', **args_service_offering)
+ instance = res['virtualmachine']
+ self.instance = instance
+
+ # Update VM
+ if instance_changed or security_groups_changed:
+ if security_groups_changed:
+ args_instance_update['securitygroupnames'] = ','.join(self.module.params.get('security_groups'))
+ res = self.query_api('updateVirtualMachine', **args_instance_update)
+ instance = res['virtualmachine']
+ self.instance = instance
+
+ # Reset SSH key
+ if ssh_key_changed:
+ # SSH key data
+ args_ssh_key = {}
+ args_ssh_key['id'] = instance['id']
+ args_ssh_key['projectid'] = self.get_project(key='id')
+ args_ssh_key['keypair'] = self.module.params.get('ssh_key')
+ instance = self.query_api('resetSSHKeyForVirtualMachine', **args_ssh_key)
+ instance = self.poll_job(instance, 'virtualmachine')
+ self.instance = instance
+
+ # Root disk size
+ if root_disk_size_changed:
+ async_result = self.query_api('resizeVolume', **args_volume_update)
+ self.poll_job(async_result, 'volume')
+
+ # Start VM again if it was running before
+ if instance_state == 'running' and start_vm:
+ instance = self.start_instance()
+ else:
+ self.module.warn("Changes won't be applied to running instances. "
+ "Use force=true to allow the instance %s to be stopped/started." % instance['name'])
+
+ # migrate to other host
+ host_changed = all([
+ instance['state'].lower() in ['starting', 'running'],
+ instance.get('hostname') is not None,
+ self.module.params.get('host') is not None,
+ self.module.params.get('host') != instance.get('hostname')
+ ])
+ if host_changed:
+ self.result['changed'] = True
+ args_host = {
+ 'virtualmachineid': instance['id'],
+ 'hostid': self.get_host_id(),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('migrateVirtualMachine', **args_host)
+ instance = self.poll_job(res, 'virtualmachine')
+
+ return instance
+
+ def recover_instance(self, instance):
+ if instance['state'].lower() in ['destroying', 'destroyed']:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('recoverVirtualMachine', id=instance['id'])
+ instance = res['virtualmachine']
+ return instance
+
+ def absent_instance(self):
+ instance = self.get_instance()
+ if instance:
+ if instance['state'].lower() not in ['expunging', 'destroying', 'destroyed']:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('destroyVirtualMachine', id=instance['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ instance = self.poll_job(res, 'virtualmachine')
+ return instance
+
+ def expunge_instance(self):
+ instance = self.get_instance()
+ if instance:
+ res = {}
+ if instance['state'].lower() in ['destroying', 'destroyed']:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('destroyVirtualMachine', id=instance['id'], expunge=True)
+
+ elif instance['state'].lower() not in ['expunging']:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('destroyVirtualMachine', id=instance['id'], expunge=True)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ res = self.poll_job(res, 'virtualmachine')
+ return instance
+
+ def stop_instance(self):
+ instance = self.get_instance()
+ # in check mode instance may not be instantiated
+ if instance:
+ if instance['state'].lower() in ['stopping', 'stopped']:
+ return instance
+
+ if instance['state'].lower() in ['starting', 'running']:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ instance = self.query_api('stopVirtualMachine', id=instance['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ instance = self.poll_job(instance, 'virtualmachine')
+ return instance
+
+ def start_instance(self):
+ instance = self.get_instance()
+ # in check mode instance may not be instantiated
+ if instance:
+ if instance['state'].lower() in ['starting', 'running']:
+ return instance
+
+ if instance['state'].lower() in ['stopped', 'stopping']:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ args = {
+ 'id': instance['id'],
+ 'hostid': self.get_host_id(),
+ }
+ instance = self.query_api('startVirtualMachine', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ instance = self.poll_job(instance, 'virtualmachine')
+ return instance
+
+ def restart_instance(self):
+ instance = self.get_instance()
+ # in check mode instance may not be instantiated
+ if instance:
+ if instance['state'].lower() in ['running', 'starting']:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ instance = self.query_api('rebootVirtualMachine', id=instance['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ instance = self.poll_job(instance, 'virtualmachine')
+
+ elif instance['state'].lower() in ['stopping', 'stopped']:
+ instance = self.start_instance()
+ return instance
+
+ def restore_instance(self):
+ instance = self.get_instance()
+ self.result['changed'] = True
+ # in check mode instance may not be instantiated
+ if instance:
+ args = {}
+ args['templateid'] = self.get_template_or_iso(key='id')
+ args['virtualmachineid'] = instance['id']
+ res = self.query_api('restoreVirtualMachine', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ instance = self.poll_job(res, 'virtualmachine')
+ return instance
+
+ def get_result(self, instance):
+ super(AnsibleCloudStackInstance, self).get_result(instance)
+ if instance:
+ self.result['user_data'] = self._get_instance_user_data(instance)
+ if 'securitygroup' in instance:
+ security_groups = []
+ for securitygroup in instance['securitygroup']:
+ security_groups.append(securitygroup['name'])
+ self.result['security_groups'] = security_groups
+ if 'affinitygroup' in instance:
+ affinity_groups = []
+ for affinitygroup in instance['affinitygroup']:
+ affinity_groups.append(affinitygroup['name'])
+ self.result['affinity_groups'] = affinity_groups
+ if 'nic' in instance:
+ for nic in instance['nic']:
+ if nic['isdefault']:
+ if 'ipaddress' in nic:
+ self.result['default_ip'] = nic['ipaddress']
+ if 'ip6address' in nic:
+ self.result['default_ip6'] = nic['ip6address']
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(),
+ display_name=dict(),
+ group=dict(),
+ state=dict(choices=['present', 'deployed', 'started', 'stopped', 'restarted', 'restored', 'absent', 'destroyed', 'expunged'], default='present'),
+ service_offering=dict(),
+ cpu=dict(type='int'),
+ cpu_speed=dict(type='int'),
+ memory=dict(type='int'),
+ template=dict(),
+ iso=dict(),
+ template_filter=dict(
+ default="executable",
+ aliases=['iso_filter'],
+ choices=['all', 'featured', 'self', 'selfexecutable', 'sharedexecutable', 'executable', 'community']
+ ),
+ networks=dict(type='list', elements='str', aliases=['network']),
+ ip_to_networks=dict(type='list', elements='dict', aliases=['ip_to_network']),
+ ip_address=dict(),
+ ip6_address=dict(),
+ disk_offering=dict(),
+ disk_size=dict(type='int'),
+ root_disk_size=dict(type='int'),
+ keyboard=dict(type='str', choices=['de', 'de-ch', 'es', 'fi', 'fr', 'fr-be', 'fr-ch', 'is', 'it', 'jp', 'nl-be', 'no', 'pt', 'uk', 'us']),
+ hypervisor=dict(),
+ host=dict(),
+ security_groups=dict(type='list', elements='str', aliases=['security_group']),
+ affinity_groups=dict(type='list', elements='str', aliases=['affinity_group']),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ user_data=dict(),
+ zone=dict(),
+ ssh_key=dict(),
+ force=dict(type='bool', default=False),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ details=dict(type='dict'),
+ poll_async=dict(type='bool', default=True),
+ allow_root_disk_shrink=dict(type='bool', default=False),
+ ))
+
+ required_together = cs_required_together()
+ required_together.extend([
+ ['cpu', 'cpu_speed', 'memory'],
+ ])
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=required_together,
+ required_one_of=(
+ ['display_name', 'name'],
+ ),
+ mutually_exclusive=(
+ ['template', 'iso'],
+ ),
+ supports_check_mode=True
+ )
+
+ acs_instance = AnsibleCloudStackInstance(module)
+
+ state = module.params.get('state')
+
+ if state in ['absent', 'destroyed']:
+ instance = acs_instance.absent_instance()
+
+ elif state in ['expunged']:
+ instance = acs_instance.expunge_instance()
+
+ elif state in ['restored']:
+ acs_instance.present_instance()
+ instance = acs_instance.restore_instance()
+
+ elif state in ['present', 'deployed']:
+ instance = acs_instance.present_instance()
+
+ elif state in ['stopped']:
+ acs_instance.present_instance(start_vm=False)
+ instance = acs_instance.stop_instance()
+
+ elif state in ['started']:
+ acs_instance.present_instance()
+ instance = acs_instance.start_instance()
+
+ elif state in ['restarted']:
+ acs_instance.present_instance()
+ instance = acs_instance.restart_instance()
+
+ if instance and 'state' in instance and instance['state'].lower() == 'error':
+ module.fail_json(msg="Instance named '%s' in error state." % module.params.get('name'))
+
+ result = acs_instance.get_result(instance)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_info.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_info.py
new file mode 100644
index 00000000..5b111bec
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_info.py
@@ -0,0 +1,370 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_instance_info
+short_description: Gathering information from the API of instances from Apache CloudStack based clouds.
+description:
+ - Gathering information from the API of an instance.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name or display name of the instance.
+ - If not specified, all instances are returned
+ type: str
+ required: false
+ domain:
+ description:
+ - Domain the instance is related to.
+ type: str
+ account:
+ description:
+ - Account the instance is related to.
+ type: str
+ project:
+ description:
+ - Project the instance is related to.
+ type: str
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Gather instance information
+ ngine_io.cloudstack.cs_instance_info:
+ name: web-vm-1
+ register: vm
+
+- name: Show the returned results of the registered variable
+ debug:
+ msg: "{{ vm }}"
+
+- name: Gather information from all instances
+ ngine_io.cloudstack.cs_instance_info:
+ register: vms
+
+- name: Show information on all instances
+ debug:
+ msg: "{{ vms }}"
+'''
+
+RETURN = '''
+---
+instances:
+ description: A list of matching instances.
+ type: list
+ returned: success
+ contains:
+ id:
+ description: UUID of the instance.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+ name:
+ description: Name of the instance.
+ returned: success
+ type: str
+ sample: web-01
+ display_name:
+ description: Display name of the instance.
+ returned: success
+ type: str
+ sample: web-01
+ group:
+ description: Group name of the instance is related.
+ returned: success
+ type: str
+ sample: web
+ created:
+ description: Date of the instance was created.
+ returned: success
+ type: str
+ sample: 2014-12-01T14:57:57+0100
+ password_enabled:
+ description: True if password setting is enabled.
+ returned: success
+ type: bool
+ sample: true
+ password:
+ description: The password of the instance if exists.
+ returned: success
+ type: str
+ sample: Ge2oe7Do
+ ssh_key:
+ description: Name of SSH key deployed to instance.
+ returned: success
+ type: str
+ sample: key@work
+ domain:
+ description: Domain the instance is related to.
+ returned: success
+ type: str
+ sample: example domain
+ account:
+ description: Account the instance is related to.
+ returned: success
+ type: str
+ sample: example account
+ project:
+ description: Name of project the instance is related to.
+ returned: success
+ type: str
+ sample: Production
+ default_ip:
+ description: Default IP address of the instance.
+ returned: success
+ type: str
+ sample: 10.23.37.42
+ public_ip:
+ description: Public IP address with instance via static NAT rule.
+ returned: success
+ type: str
+ sample: 1.2.3.4
+ iso:
+ description: Name of ISO the instance was deployed with.
+ returned: success
+ type: str
+ sample: Debian-8-64bit
+ template:
+ description: Name of template the instance was deployed with.
+ returned: success
+ type: str
+ sample: Debian-8-64bit
+ service_offering:
+ description: Name of the service offering the instance has.
+ returned: success
+ type: str
+ sample: 2cpu_2gb
+ zone:
+ description: Name of zone the instance is in.
+ returned: success
+ type: str
+ sample: ch-gva-2
+ state:
+ description: State of the instance.
+ returned: success
+ type: str
+ sample: Running
+ security_groups:
+ description: Security groups the instance is in.
+ returned: success
+ type: list
+ sample: '[ "default" ]'
+ affinity_groups:
+ description: Affinity groups the instance is in.
+ returned: success
+ type: list
+ sample: '[ "webservers" ]'
+ tags:
+ description: List of resource tags associated with the instance.
+ returned: success
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+ hypervisor:
+ description: Hypervisor related to this instance.
+ returned: success
+ type: str
+ sample: KVM
+ host:
+ description: Host the instance is running on.
+ returned: success and instance is running
+ type: str
+ sample: host01.example.com
+ instance_name:
+ description: Internal name of the instance (ROOT admin only).
+ returned: success
+ type: str
+ sample: i-44-3992-VM
+ volumes:
+ description: List of dictionaries of the volumes attached to the instance.
+ returned: success
+ type: list
+ sample: '[ { name: "ROOT-1369", type: "ROOT", size: 10737418240 }, { name: "data01, type: "DATADISK", size: 10737418240 } ]'
+ nic:
+ description: List of dictionaries of the instance nics.
+ returned: success
+ type: complex
+ contains:
+ broadcasturi:
+ description: The broadcast uri of the nic.
+ returned: success
+ type: str
+ sample: vlan://2250
+ gateway:
+ description: The gateway of the nic.
+ returned: success
+ type: str
+ sample: 10.1.2.1
+ id:
+ description: The ID of the nic.
+ returned: success
+ type: str
+ sample: 5dc74fa3-2ec3-48a0-9e0d-6f43365336a9
+ ipaddress:
+ description: The ip address of the nic.
+ returned: success
+ type: str
+ sample: 10.1.2.3
+ isdefault:
+ description: True if nic is default, false otherwise.
+ returned: success
+ type: bool
+ sample: true
+ isolationuri:
+ description: The isolation uri of the nic.
+ returned: success
+ type: str
+ sample: vlan://2250
+ macaddress:
+ description: The mac address of the nic.
+ returned: success
+ type: str
+ sample: 06:a2:03:00:08:12
+ netmask:
+ description: The netmask of the nic.
+ returned: success
+ type: str
+ sample: 255.255.255.0
+ networkid:
+ description: The ID of the corresponding network.
+ returned: success
+ type: str
+ sample: 432ce27b-c2bb-4e12-a88c-a919cd3a3017
+ networkname:
+ description: The name of the corresponding network.
+ returned: success
+ type: str
+ sample: network1
+ traffictype:
+ description: The traffic type of the nic.
+ returned: success
+ type: str
+ sample: Guest
+ type:
+ description: The type of the network.
+ returned: success
+ type: str
+ sample: Shared
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec
+
+
+class AnsibleCloudStackInstanceInfo(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackInstanceInfo, self).__init__(module)
+ self.returns = {
+ 'group': 'group',
+ 'hypervisor': 'hypervisor',
+ 'instancename': 'instance_name',
+ 'publicip': 'public_ip',
+ 'passwordenabled': 'password_enabled',
+ 'password': 'password',
+ 'serviceofferingname': 'service_offering',
+ 'isoname': 'iso',
+ 'templatename': 'template',
+ 'keypair': 'ssh_key',
+ 'hostname': 'host',
+ }
+
+ def get_instances(self):
+ instance_name = self.module.params.get('name')
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'fetch_list': True,
+ }
+ # Do not pass zoneid, as the instance name must be unique across zones.
+ instances = self.query_api('listVirtualMachines', **args)
+ if not instance_name:
+ return instances or []
+ if instances:
+ for v in instances:
+ if instance_name.lower() in [v['name'].lower(), v['displayname'].lower(), v['id']]:
+ return [v]
+ return []
+
+ def get_volumes(self, instance):
+ volume_details = []
+ if instance:
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'virtualmachineid': instance['id'],
+ 'fetch_list': True,
+ }
+
+ volumes = self.query_api('listVolumes', **args)
+ if volumes:
+ for vol in volumes:
+ volume_details.append({'size': vol['size'], 'type': vol['type'], 'name': vol['name']})
+ return volume_details
+
+ def run(self):
+ instances = self.get_instances()
+ if self.module.params.get('name') and not instances:
+ self.module.fail_json(msg="Instance not found: %s" % self.module.params.get('name'))
+ return {
+ 'instances': [self.update_result(resource) for resource in instances]
+ }
+
+ def update_result(self, instance, result=None):
+ result = super(AnsibleCloudStackInstanceInfo, self).update_result(instance, result)
+ if instance:
+ if 'securitygroup' in instance:
+ security_groups = []
+ for securitygroup in instance['securitygroup']:
+ security_groups.append(securitygroup['name'])
+ result['security_groups'] = security_groups
+ if 'affinitygroup' in instance:
+ affinity_groups = []
+ for affinitygroup in instance['affinitygroup']:
+ affinity_groups.append(affinitygroup['name'])
+ result['affinity_groups'] = affinity_groups
+ if 'nic' in instance:
+ for nic in instance['nic']:
+ if nic['isdefault'] and 'ipaddress' in nic:
+ result['default_ip'] = nic['ipaddress']
+ result['nic'] = instance['nic']
+ volumes = self.get_volumes(instance)
+ if volumes:
+ result['volumes'] = volumes
+ return result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ acs_instance_info = AnsibleCloudStackInstanceInfo(module=module)
+ cs_instance_info = acs_instance_info.run()
+ module.exit_json(**cs_instance_info)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic.py
new file mode 100644
index 00000000..11ea45fc
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic.py
@@ -0,0 +1,285 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, Marc-Aurèle Brothier @marcaurele
+# Copyright (c) 2017, 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: cs_instance_nic
+short_description: Manages NICs of an instance on Apache CloudStack based clouds.
+description:
+ - Add and remove nic to and from network
+author:
+ - Marc-Aurèle Brothier (@marcaurele)
+ - René Moser (@resmo)
+version_added: 0.1.0
+options:
+ vm:
+ description:
+ - Name of instance.
+ required: true
+ type: str
+ aliases: [ name ]
+ network:
+ description:
+ - Name of the network.
+ type: str
+ required: true
+ ip_address:
+ description:
+ - IP address to be used for the nic.
+ type: str
+ vpc:
+ description:
+ - Name of the VPC the I(vm) is related to.
+ type: str
+ domain:
+ description:
+ - Domain the instance is related to.
+ type: str
+ account:
+ description:
+ - Account the instance is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the instance is deployed in.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the instance is deployed in.
+ - If not set, default zone is used.
+ type: str
+ state:
+ description:
+ - State of the nic.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Add a nic on another network
+ ngine_io.cloudstack.cs_instance_nic:
+ vm: privnet
+ network: privNetForBasicZone
+
+- name: Ensure IP address on a nic
+ ngine_io.cloudstack.cs_instance_nic:
+ vm: privnet
+ ip_address: 10.10.11.32
+ network: privNetForBasicZone
+
+- name: Remove a secondary nic
+ ngine_io.cloudstack.cs_instance_nic:
+ vm: privnet
+ state: absent
+ network: privNetForBasicZone
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the nic.
+ returned: success
+ type: str
+ sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8
+vm:
+ description: Name of the VM.
+ returned: success
+ type: str
+ sample: web-01
+ip_address:
+ description: Primary IP of the NIC.
+ returned: success
+ type: str
+ sample: 10.10.10.10
+netmask:
+ description: Netmask of the NIC.
+ returned: success
+ type: str
+ sample: 255.255.255.0
+mac_address:
+ description: MAC address of the NIC.
+ returned: success
+ type: str
+ sample: 02:00:33:31:00:e4
+network:
+ description: Name of the network if not default.
+ returned: success
+ type: str
+ sample: sync network
+domain:
+ description: Domain the VM is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the VM is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project the VM is related to.
+ returned: success
+ type: str
+ sample: Production
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackInstanceNic(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackInstanceNic, self).__init__(module)
+ self.nic = None
+ self.returns = {
+ 'ipaddress': 'ip_address',
+ 'macaddress': 'mac_address',
+ 'netmask': 'netmask',
+ }
+
+ def get_nic(self):
+ if self.nic:
+ return self.nic
+ args = {
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'networkid': self.get_network(key='id'),
+ }
+ nics = self.query_api('listNics', **args)
+ if nics:
+ self.nic = nics['nic'][0]
+ return self.nic
+ return None
+
+ def get_nic_from_result(self, result):
+ for nic in result.get('nic') or []:
+ if nic['networkid'] == self.get_network(key='id'):
+ return nic
+
+ def add_nic(self):
+ self.result['changed'] = True
+ args = {
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'networkid': self.get_network(key='id'),
+ 'ipaddress': self.module.params.get('ip_address'),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('addNicToVirtualMachine', **args)
+
+ if self.module.params.get('poll_async'):
+ vm = self.poll_job(res, 'virtualmachine')
+ self.nic = self.get_nic_from_result(result=vm)
+ return self.nic
+
+ def update_nic(self, nic):
+ # Do not try to update if no IP address is given
+ ip_address = self.module.params.get('ip_address')
+ if not ip_address:
+ return nic
+
+ args = {
+ 'nicid': nic['id'],
+ 'ipaddress': ip_address,
+ }
+ if self.has_changed(args, nic, ['ipaddress']):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateVmNicIp', **args)
+
+ if self.module.params.get('poll_async'):
+ vm = self.poll_job(res, 'virtualmachine')
+ self.nic = self.get_nic_from_result(result=vm)
+ return self.nic
+
+ def remove_nic(self, nic):
+ self.result['changed'] = True
+ args = {
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'nicid': nic['id'],
+ }
+ if not self.module.check_mode:
+ res = self.query_api('removeNicFromVirtualMachine', **args)
+
+ if self.module.params.get('poll_async'):
+ self.poll_job(res, 'virtualmachine')
+ return nic
+
+ def present_nic(self):
+ nic = self.get_nic()
+ if not nic:
+ nic = self.add_nic()
+ else:
+ nic = self.update_nic(nic)
+ return nic
+
+ def absent_nic(self):
+ nic = self.get_nic()
+ if nic:
+ return self.remove_nic(nic)
+ return nic
+
+ def get_result(self, nic):
+ super(AnsibleCloudStackInstanceNic, self).get_result(nic)
+ if nic and not self.module.params.get('network'):
+ self.module.params['network'] = nic.get('networkid')
+ self.result['network'] = self.get_network(key='name')
+ self.result['vm'] = self.get_vm(key='name')
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ vm=dict(required=True, aliases=['name']),
+ network=dict(required=True),
+ vpc=dict(),
+ ip_address=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ zone=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True,
+ )
+
+ acs_nic = AnsibleCloudStackInstanceNic(module)
+
+ state = module.params.get('state')
+ if state == 'absent':
+ nic = acs_nic.absent_nic()
+ else:
+ nic = acs_nic.present_nic()
+
+ result = acs_nic.get_result(nic)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic_secondaryip.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic_secondaryip.py
new file mode 100644
index 00000000..7dabe7d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic_secondaryip.py
@@ -0,0 +1,267 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, 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: cs_instance_nic_secondaryip
+short_description: Manages secondary IPs of an instance on Apache CloudStack based clouds.
+description:
+ - Add and remove secondary IPs to and from a NIC of an instance.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ vm:
+ description:
+ - Name of instance.
+ type: str
+ required: true
+ aliases: [ name ]
+ network:
+ description:
+ - Name of the network.
+ - Required to find the NIC if instance has multiple networks assigned.
+ type: str
+ vm_guest_ip:
+ description:
+ - Secondary IP address to be added to the instance nic.
+ - If not set, the API always returns a new IP address and idempotency is not given.
+ type: str
+ aliases: [ secondary_ip ]
+ vpc:
+ description:
+ - Name of the VPC the I(vm) is related to.
+ type: str
+ domain:
+ description:
+ - Domain the instance is related to.
+ type: str
+ account:
+ description:
+ - Account the instance is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the instance is deployed in.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the instance is deployed in.
+ - If not set, default zone is used.
+ type: str
+ state:
+ description:
+ - State of the ipaddress.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+
+'''
+
+EXAMPLES = '''
+- name: Assign a specific IP to the default NIC of the VM
+ ngine_io.cloudstack.cs_instance_nic_secondaryip:
+ vm: customer_xy
+ vm_guest_ip: 10.10.10.10
+
+# Note: If vm_guest_ip is not set, you will get a new IP address on every run.
+- name: Assign an IP to the default NIC of the VM
+ ngine_io.cloudstack.cs_instance_nic_secondaryip:
+ vm: customer_xy
+
+- name: Remove a specific IP from the default NIC
+ ngine_io.cloudstack.cs_instance_nic_secondaryip:
+ vm: customer_xy
+ vm_guest_ip: 10.10.10.10
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the NIC.
+ returned: success
+ type: str
+ sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8
+vm:
+ description: Name of the VM.
+ returned: success
+ type: str
+ sample: web-01
+ip_address:
+ description: Primary IP of the NIC.
+ returned: success
+ type: str
+ sample: 10.10.10.10
+netmask:
+ description: Netmask of the NIC.
+ returned: success
+ type: str
+ sample: 255.255.255.0
+mac_address:
+ description: MAC address of the NIC.
+ returned: success
+ type: str
+ sample: 02:00:33:31:00:e4
+vm_guest_ip:
+ description: Secondary IP of the NIC.
+ returned: success
+ type: str
+ sample: 10.10.10.10
+network:
+ description: Name of the network if not default.
+ returned: success
+ type: str
+ sample: sync network
+domain:
+ description: Domain the VM is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the VM is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project the VM is related to.
+ returned: success
+ type: str
+ sample: Production
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackInstanceNicSecondaryIp(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackInstanceNicSecondaryIp, self).__init__(module)
+ self.vm_guest_ip = self.module.params.get('vm_guest_ip')
+ self.nic = None
+ self.returns = {
+ 'ipaddress': 'ip_address',
+ 'macaddress': 'mac_address',
+ 'netmask': 'netmask',
+ }
+
+ def get_nic(self):
+ if self.nic:
+ return self.nic
+ args = {
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'networkid': self.get_network(key='id'),
+ }
+ nics = self.query_api('listNics', **args)
+ if nics:
+ self.nic = nics['nic'][0]
+ return self.nic
+ self.fail_json(msg="NIC for VM %s in network %s not found" % (self.get_vm(key='name'), self.get_network(key='name')))
+
+ def get_secondary_ip(self):
+ nic = self.get_nic()
+ if self.vm_guest_ip:
+ secondary_ips = nic.get('secondaryip') or []
+ for secondary_ip in secondary_ips:
+ if secondary_ip['ipaddress'] == self.vm_guest_ip:
+ return secondary_ip
+ return None
+
+ def present_nic_ip(self):
+ nic = self.get_nic()
+ if not self.get_secondary_ip():
+ self.result['changed'] = True
+ args = {
+ 'nicid': nic['id'],
+ 'ipaddress': self.vm_guest_ip,
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('addIpToNic', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ nic = self.poll_job(res, 'nicsecondaryip')
+ # Save result for RETURNS
+ self.vm_guest_ip = nic['ipaddress']
+ return nic
+
+ def absent_nic_ip(self):
+ nic = self.get_nic()
+ secondary_ip = self.get_secondary_ip()
+ if secondary_ip:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('removeIpFromNic', id=secondary_ip['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'nicsecondaryip')
+ return nic
+
+ def get_result(self, nic):
+ super(AnsibleCloudStackInstanceNicSecondaryIp, self).get_result(nic)
+ if nic and not self.module.params.get('network'):
+ self.module.params['network'] = nic.get('networkid')
+ self.result['network'] = self.get_network(key='name')
+ self.result['vm'] = self.get_vm(key='name')
+ self.result['vm_guest_ip'] = self.vm_guest_ip
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ vm=dict(required=True, aliases=['name']),
+ vm_guest_ip=dict(aliases=['secondary_ip']),
+ network=dict(),
+ vpc=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ zone=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True,
+ required_if=([
+ ('state', 'absent', ['vm_guest_ip'])
+ ])
+ )
+
+ acs_instance_nic_secondaryip = AnsibleCloudStackInstanceNicSecondaryIp(module)
+ state = module.params.get('state')
+
+ if state == 'absent':
+ nic = acs_instance_nic_secondaryip.absent_nic_ip()
+ else:
+ nic = acs_instance_nic_secondaryip.present_nic_ip()
+
+ result = acs_instance_nic_secondaryip.get_result(nic)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_password_reset.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_password_reset.py
new file mode 100644
index 00000000..58b9b741
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_password_reset.py
@@ -0,0 +1,151 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2018, Gregor Riepl <onitake@gmail.com>
+# based on cs_sshkeypair (c) 2015, 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: cs_instance_password_reset
+short_description: Allows resetting VM the default passwords on Apache CloudStack based clouds.
+description:
+ - Resets the default user account's password on an instance.
+ - Requires cloud-init to be installed in the virtual machine.
+ - The passwordenabled flag must be set on the template associated with the VM.
+author: Gregor Riepl (@onitake)
+version_added: 0.1.0
+options:
+ vm:
+ description:
+ - Name of the virtual machine to reset the password on.
+ type: str
+ required: true
+ domain:
+ description:
+ - Name of the domain the virtual machine belongs to.
+ type: str
+ account:
+ description:
+ - Account the virtual machine belongs to.
+ type: str
+ project:
+ description:
+ - Name of the project the virtual machine belongs to.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the instance is deployed.
+ - If not set, the default zone is used.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: stop the virtual machine before resetting the password
+ ngine_io.cloudstack.cs_instance:
+ name: myvirtualmachine
+ state: stopped
+
+- name: reset and get new default password
+ ngine_io.cloudstack.cs_instance_password_reset:
+ vm: myvirtualmachine
+ register: root
+
+- debug:
+ msg: "new default password is {{ root.password }}"
+
+- name: boot the virtual machine to activate the new password
+ ngine_io.cloudstack.cs_instance:
+ name: myvirtualmachine
+ state: started
+ when: root is changed
+'''
+
+RETURN = '''
+---
+id:
+ description: ID of the virtual machine.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+password:
+ description: The new default password.
+ returned: success
+ type: str
+ sample: ahQu5nuNge3keesh
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_required_together,
+ cs_argument_spec
+)
+
+
+class AnsibleCloudStackPasswordReset(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackPasswordReset, self).__init__(module)
+ self.returns = {
+ 'password': 'password',
+ }
+ self.password = None
+
+ def reset_password(self):
+ args = {
+ 'id': self.get_vm(key='id'),
+ }
+
+ res = None
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('resetPasswordForVirtualMachine', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ res = self.poll_job(res, 'virtualmachine')
+
+ if res and 'password' in res:
+ self.password = res['password']
+
+ return self.password
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ vm=dict(required=True),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ zone=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_password = AnsibleCloudStackPasswordReset(module)
+ password = acs_password.reset_password()
+ result = acs_password.get_result({'password': password})
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instancegroup.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instancegroup.py
new file mode 100644
index 00000000..56783b2a
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instancegroup.py
@@ -0,0 +1,181 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_instancegroup
+short_description: Manages instance groups on Apache CloudStack based clouds.
+description:
+ - Create and remove instance groups.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the instance group.
+ type: str
+ required: true
+ domain:
+ description:
+ - Domain the instance group is related to.
+ type: str
+ account:
+ description:
+ - Account the instance group is related to.
+ type: str
+ project:
+ description:
+ - Project the instance group is related to.
+ type: str
+ state:
+ description:
+ - State of the instance group.
+ type: str
+ default: present
+ choices: [ present, absent ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create an instance group
+ ngine_io.cloudstack.cs_instancegroup:
+ name: loadbalancers
+
+- name: Remove an instance group
+ ngine_io.cloudstack.cs_instancegroup:
+ name: loadbalancers
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the instance group.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: Name of the instance group.
+ returned: success
+ type: str
+ sample: webservers
+created:
+ description: Date when the instance group was created.
+ returned: success
+ type: str
+ sample: 2015-05-03T15:05:51+0200
+domain:
+ description: Domain the instance group is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the instance group is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Project the instance group is related to.
+ returned: success
+ type: str
+ sample: example project
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackInstanceGroup(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackInstanceGroup, self).__init__(module)
+ self.instance_group = None
+
+ def get_instance_group(self):
+ if self.instance_group:
+ return self.instance_group
+
+ name = self.module.params.get('name')
+
+ args = {
+ 'account': self.get_account('name'),
+ 'domainid': self.get_domain('id'),
+ 'projectid': self.get_project('id'),
+ 'fetch_list': True,
+ }
+ instance_groups = self.query_api('listInstanceGroups', **args)
+ if instance_groups:
+ for g in instance_groups:
+ if name in [g['name'], g['id']]:
+ self.instance_group = g
+ break
+ return self.instance_group
+
+ def present_instance_group(self):
+ instance_group = self.get_instance_group()
+ if not instance_group:
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'account': self.get_account('name'),
+ 'domainid': self.get_domain('id'),
+ 'projectid': self.get_project('id'),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createInstanceGroup', **args)
+ instance_group = res['instancegroup']
+ return instance_group
+
+ def absent_instance_group(self):
+ instance_group = self.get_instance_group()
+ if instance_group:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ self.query_api('deleteInstanceGroup', id=instance_group['id'])
+ return instance_group
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ state=dict(default='present', choices=['present', 'absent']),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_ig = AnsibleCloudStackInstanceGroup(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ instance_group = acs_ig.absent_instance_group()
+ else:
+ instance_group = acs_ig.present_instance_group()
+
+ result = acs_ig.get_result(instance_group)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_ip_address.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_ip_address.py
new file mode 100644
index 00000000..04236d3d
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_ip_address.py
@@ -0,0 +1,279 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, Darren Worrall <darren@iweb.co.uk>
+# Copyright (c) 2015, 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: cs_ip_address
+short_description: Manages public IP address associations on Apache CloudStack based clouds.
+description:
+ - Acquires and associates a public IP to an account or project.
+ - Due to API limitations this is not an idempotent call, so be sure to only
+ conditionally call this when I(state=present).
+ - Tagging the IP address can also make the call idempotent.
+author:
+ - Darren Worrall (@dazworrall)
+ - René Moser (@resmo)
+version_added: 0.1.0
+options:
+ ip_address:
+ description:
+ - Public IP address.
+ - Required if I(state=absent) and I(tags) is not set.
+ type: str
+ domain:
+ description:
+ - Domain the IP address is related to.
+ type: str
+ network:
+ description:
+ - Network the IP address is related to.
+ - Mutually exclusive with I(vpc).
+ type: str
+ vpc:
+ description:
+ - VPC the IP address is related to.
+ - Mutually exclusive with I(network).
+ type: str
+ account:
+ description:
+ - Account the IP address is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the IP address is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the IP address is in.
+ - If not set, default zone is used.
+ type: str
+ state:
+ description:
+ - State of the IP address.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - Tags can be used as an unique identifier for the IP Addresses.
+ - In this case, at least one of them must be unique to ensure idempotency.
+ type: list
+ elements: dict
+ aliases: [ tag ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Associate an IP address conditionally
+ ngine_io.cloudstack.cs_ip_address:
+ network: My Network
+ register: ip_address
+ when: instance.public_ip is undefined
+
+- name: Disassociate an IP address
+ ngine_io.cloudstack.cs_ip_address:
+ ip_address: 1.2.3.4
+ state: absent
+
+- name: Associate an IP address with tags
+ ngine_io.cloudstack.cs_ip_address:
+ network: My Network
+ tags:
+ - key: myCustomID
+ value: 5510c31a-416e-11e8-9013-02000a6b00bf
+ register: ip_address
+
+- name: Disassociate an IP address with tags
+ ngine_io.cloudstack.cs_ip_address:
+ state: absent
+ tags:
+ - key: myCustomID
+ value: 5510c31a-416e-11e8-9013-02000a6b00bf
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the Public IP address.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+ip_address:
+ description: Public IP address.
+ returned: success
+ type: str
+ sample: 1.2.3.4
+zone:
+ description: Name of zone the IP address is related to.
+ returned: success
+ type: str
+ sample: ch-gva-2
+project:
+ description: Name of project the IP address is related to.
+ returned: success
+ type: str
+ sample: Production
+account:
+ description: Account the IP address is related to.
+ returned: success
+ type: str
+ sample: example account
+domain:
+ description: Domain the IP address is related to.
+ returned: success
+ type: str
+ sample: example domain
+tags:
+ description: List of resource tags associated with the IP address.
+ returned: success
+ type: dict
+ sample: '[ { "key": "myCustomID", "value": "5510c31a-416e-11e8-9013-02000a6b00bf" } ]'
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackIPAddress(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackIPAddress, self).__init__(module)
+ self.returns = {
+ 'ipaddress': 'ip_address',
+ }
+
+ def get_ip_address(self, key=None):
+ if self.ip_address:
+ return self._get_by_key(key, self.ip_address)
+ args = {
+ 'ipaddress': self.module.params.get('ip_address'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'vpcid': self.get_vpc(key='id'),
+ }
+ ip_addresses = self.query_api('listPublicIpAddresses', **args)
+
+ if ip_addresses:
+ tags = self.module.params.get('tags')
+ for ip_addr in ip_addresses['publicipaddress']:
+ if ip_addr['ipaddress'] == args['ipaddress'] != '':
+ self.ip_address = ip_addresses['publicipaddress'][0]
+ elif tags:
+ if sorted([tag for tag in tags if tag in ip_addr['tags']]) == sorted(tags):
+ self.ip_address = ip_addr
+ return self._get_by_key(key, self.ip_address)
+
+ def present_ip_address(self):
+ ip_address = self.get_ip_address()
+
+ if not ip_address:
+ ip_address = self.associate_ip_address(ip_address)
+
+ if ip_address:
+ ip_address = self.ensure_tags(resource=ip_address, resource_type='publicipaddress')
+
+ return ip_address
+
+ def associate_ip_address(self, ip_address):
+ self.result['changed'] = True
+ args = {
+ # ipaddress only works with CloudStack >=v4.13
+ 'ipaddress': self.module.params.get('ip_address'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ # For the VPC case networkid is irrelevant, special case and we have to ignore it here.
+ 'networkid': self.get_network(key='id') if not self.module.params.get('vpc') else None,
+ 'zoneid': self.get_zone(key='id'),
+ 'vpcid': self.get_vpc(key='id'),
+ }
+ ip_address = None
+ if not self.module.check_mode:
+ res = self.query_api('associateIpAddress', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ ip_address = self.poll_job(res, 'ipaddress')
+ return ip_address
+
+ def disassociate_ip_address(self):
+ ip_address = self.get_ip_address()
+ if not ip_address:
+ return None
+ if ip_address['isstaticnat']:
+ self.module.fail_json(msg="IP address is allocated via static nat")
+
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ self.module.params['tags'] = []
+ ip_address = self.ensure_tags(resource=ip_address, resource_type='publicipaddress')
+
+ res = self.query_api('disassociateIpAddress', id=ip_address['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'ipaddress')
+ return ip_address
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ ip_address=dict(required=False),
+ state=dict(choices=['present', 'absent'], default='present'),
+ vpc=dict(),
+ network=dict(),
+ zone=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ required_if=[
+ ('state', 'absent', ['ip_address', 'tags'], True),
+ ],
+ mutually_exclusive=(
+ ['vpc', 'network'],
+ ),
+ supports_check_mode=True
+ )
+
+ acs_ip_address = AnsibleCloudStackIPAddress(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ ip_address = acs_ip_address.disassociate_ip_address()
+ else:
+ ip_address = acs_ip_address.present_ip_address()
+
+ result = acs_ip_address.get_result(ip_address)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_iso.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_iso.py
new file mode 100644
index 00000000..cecca5eb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_iso.py
@@ -0,0 +1,436 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_iso
+short_description: Manages ISO images on Apache CloudStack based clouds.
+description:
+ - Register and remove ISO images.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the ISO.
+ type: str
+ required: true
+ display_text:
+ description:
+ - Display text of the ISO.
+ - If not specified, I(name) will be used.
+ type: str
+ url:
+ description:
+ - URL where the ISO can be downloaded from. Required if I(state) is present.
+ type: str
+ os_type:
+ description:
+ - Name of the OS that best represents the OS of this ISO. If the iso is bootable this parameter needs to be passed. Required if I(state) is present.
+ type: str
+ is_ready:
+ description:
+ - This flag is used for searching existing ISOs. If set to C(yes), it will only list ISO ready for deployment e.g.
+ successfully downloaded and installed. Recommended to set it to C(no).
+ type: bool
+ default: no
+ is_public:
+ description:
+ - Register the ISO to be publicly available to all users. Only used if I(state) is present.
+ type: bool
+ is_featured:
+ description:
+ - Register the ISO to be featured. Only used if I(state) is present.
+ type: bool
+ is_dynamically_scalable:
+ description:
+ - Register the ISO having XS/VMware tools installed inorder to support dynamic scaling of VM cpu/memory. Only used if I(state) is present.
+ type: bool
+ checksum:
+ description:
+ - The MD5 checksum value of this ISO. If set, we search by checksum instead of name.
+ type: str
+ bootable:
+ description:
+ - Register the ISO to be bootable. Only used if I(state) is present.
+ type: bool
+ domain:
+ description:
+ - Domain the ISO is related to.
+ type: str
+ account:
+ description:
+ - Account the ISO is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the ISO to be registered in.
+ type: str
+ zone:
+ description:
+ - Name of the zone you wish the ISO to be registered or deleted from.
+ - If not specified, first zone found will be used.
+ type: str
+ cross_zones:
+ description:
+ - Whether the ISO should be synced or removed across zones.
+ - Mutually exclusive with I(zone).
+ type: bool
+ default: no
+ iso_filter:
+ description:
+ - Name of the filter used to search for the ISO.
+ type: str
+ default: self
+ choices: [ featured, self, selfexecutable,sharedexecutable,executable, community ]
+ state:
+ description:
+ - State of the ISO.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "To delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Register an ISO if ISO name does not already exist
+ ngine_io.cloudstack.cs_iso:
+ name: Debian 7 64-bit
+ url: http://mirror.switch.ch/ftp/mirror/debian-cd/current/amd64/iso-cd/debian-7.7.0-amd64-netinst.iso
+ os_type: Debian GNU/Linux 7(64-bit)
+
+- name: Register an ISO with given name if ISO md5 checksum does not already exist
+ ngine_io.cloudstack.cs_iso:
+ name: Debian 7 64-bit
+ url: http://mirror.switch.ch/ftp/mirror/debian-cd/current/amd64/iso-cd/debian-7.7.0-amd64-netinst.iso
+ os_type: Debian GNU/Linux 7(64-bit)
+ checksum: 0b31bccccb048d20b551f70830bb7ad0
+
+- name: Remove an ISO by name
+ ngine_io.cloudstack.cs_iso:
+ name: Debian 7 64-bit
+ state: absent
+
+- name: Remove an ISO by checksum
+ ngine_io.cloudstack.cs_iso:
+ name: Debian 7 64-bit
+ checksum: 0b31bccccb048d20b551f70830bb7ad0
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the ISO.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+name:
+ description: Name of the ISO.
+ returned: success
+ type: str
+ sample: Debian 7 64-bit
+display_text:
+ description: Text to be displayed of the ISO.
+ returned: success
+ type: str
+ sample: Debian 7.7 64-bit minimal 2015-03-19
+zone:
+ description: Name of zone the ISO is registered in.
+ returned: success
+ type: str
+ sample: zuerich
+status:
+ description: Status of the ISO.
+ returned: success
+ type: str
+ sample: Successfully Installed
+is_ready:
+ description: True if the ISO is ready to be deployed from.
+ returned: success
+ type: bool
+ sample: true
+is_public:
+ description: True if the ISO is public.
+ returned: success
+ type: bool
+ sample: true
+bootable:
+ description: True if the ISO is bootable.
+ returned: success
+ type: bool
+ sample: true
+is_featured:
+ description: True if the ISO is featured.
+ returned: success
+ type: bool
+ sample: true
+format:
+ description: Format of the ISO.
+ returned: success
+ type: str
+ sample: ISO
+os_type:
+ description: Typo of the OS.
+ returned: success
+ type: str
+ sample: CentOS 6.5 (64-bit)
+checksum:
+ description: MD5 checksum of the ISO.
+ returned: success
+ type: str
+ sample: 0b31bccccb048d20b551f70830bb7ad0
+created:
+ description: Date of registering.
+ returned: success
+ type: str
+ sample: 2015-03-29T14:57:06+0200
+cross_zones:
+ description: true if the ISO is managed across all zones, false otherwise.
+ returned: success
+ type: bool
+ sample: false
+domain:
+ description: Domain the ISO is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the ISO is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Project the ISO is related to.
+ returned: success
+ type: str
+ sample: example project
+tags:
+ description: List of resource tags associated with the ISO.
+ returned: success
+ type: dict
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackIso(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackIso, self).__init__(module)
+ self.returns = {
+ 'checksum': 'checksum',
+ 'status': 'status',
+ 'isready': 'is_ready',
+ 'crossZones': 'cross_zones',
+ 'format': 'format',
+ 'ostypename': 'os_type',
+ 'isfeatured': 'is_featured',
+ 'bootable': 'bootable',
+ 'ispublic': 'is_public',
+
+ }
+ self.iso = None
+
+ def _get_common_args(self):
+ return {
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ 'isdynamicallyscalable': self.module.params.get('is_dynamically_scalable'),
+ 'ostypeid': self.get_os_type('id'),
+ 'bootable': self.module.params.get('bootable'),
+ }
+
+ def register_iso(self):
+ args = self._get_common_args()
+ args.update({
+ 'domainid': self.get_domain('id'),
+ 'account': self.get_account('name'),
+ 'projectid': self.get_project('id'),
+ 'checksum': self.module.params.get('checksum'),
+ 'isfeatured': self.module.params.get('is_featured'),
+ 'ispublic': self.module.params.get('is_public'),
+ })
+
+ if not self.module.params.get('cross_zones'):
+ args['zoneid'] = self.get_zone(key='id')
+ else:
+ args['zoneid'] = -1
+
+ if args['bootable'] and not args['ostypeid']:
+ self.module.fail_json(msg="OS type 'os_type' is required if 'bootable=true'.")
+
+ args['url'] = self.module.params.get('url')
+ if not args['url']:
+ self.module.fail_json(msg="URL is required.")
+
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('registerIso', **args)
+ self.iso = res['iso'][0]
+ return self.iso
+
+ def present_iso(self):
+ iso = self.get_iso()
+ if not iso:
+ iso = self.register_iso()
+ else:
+ iso = self.update_iso(iso)
+
+ if iso:
+ iso = self.ensure_tags(resource=iso, resource_type='ISO')
+ self.iso = iso
+ return iso
+
+ def update_iso(self, iso):
+ args = self._get_common_args()
+ args.update({
+ 'id': iso['id'],
+ })
+ if self.has_changed(args, iso):
+ self.result['changed'] = True
+
+ if not self.module.params.get('cross_zones'):
+ args['zoneid'] = self.get_zone(key='id')
+ else:
+ # Workaround API does not return cross_zones=true
+ self.result['cross_zones'] = True
+ args['zoneid'] = -1
+
+ if not self.module.check_mode:
+ res = self.query_api('updateIso', **args)
+ self.iso = res['iso']
+ return self.iso
+
+ def get_iso(self):
+ if not self.iso:
+ args = {
+ 'isready': self.module.params.get('is_ready'),
+ 'isofilter': self.module.params.get('iso_filter'),
+ 'domainid': self.get_domain('id'),
+ 'account': self.get_account('name'),
+ 'projectid': self.get_project('id'),
+ }
+
+ if not self.module.params.get('cross_zones'):
+ args['zoneid'] = self.get_zone(key='id')
+
+ # if checksum is set, we only look on that.
+ checksum = self.module.params.get('checksum')
+ if not checksum:
+ args['name'] = self.module.params.get('name')
+
+ isos = self.query_api('listIsos', **args)
+ if isos:
+ if not checksum:
+ self.iso = isos['iso'][0]
+ else:
+ for i in isos['iso']:
+ if i['checksum'] == checksum:
+ self.iso = i
+ break
+ return self.iso
+
+ def absent_iso(self):
+ iso = self.get_iso()
+ if iso:
+ self.result['changed'] = True
+
+ args = {
+ 'id': iso['id'],
+ 'projectid': self.get_project('id'),
+ }
+
+ if not self.module.params.get('cross_zones'):
+ args['zoneid'] = self.get_zone(key='id')
+
+ if not self.module.check_mode:
+ res = self.query_api('deleteIso', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'iso')
+ return iso
+
+ def get_result(self, iso):
+ super(AnsibleCloudStackIso, self).get_result(iso)
+ # Workaround API does not return cross_zones=true
+ if self.module.params.get('cross_zones'):
+ self.result['cross_zones'] = True
+ if 'zone' in self.result:
+ del self.result['zone']
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ display_text=dict(),
+ url=dict(),
+ os_type=dict(),
+ zone=dict(),
+ cross_zones=dict(type='bool', default=False),
+ iso_filter=dict(default='self', choices=['featured', 'self', 'selfexecutable', 'sharedexecutable', 'executable', 'community']),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ checksum=dict(),
+ is_ready=dict(type='bool', default=False),
+ bootable=dict(type='bool'),
+ is_featured=dict(type='bool'),
+ is_public=dict(type='bool'),
+ is_dynamically_scalable=dict(type='bool'),
+ state=dict(choices=['present', 'absent'], default='present'),
+ poll_async=dict(type='bool', default=True),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ mutually_exclusive=(
+ ['zone', 'cross_zones'],
+ ),
+ supports_check_mode=True
+ )
+
+ acs_iso = AnsibleCloudStackIso(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ iso = acs_iso.absent_iso()
+ else:
+ iso = acs_iso.present_iso()
+
+ result = acs_iso.get_result(iso)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule.py
new file mode 100644
index 00000000..12a7d13a
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule.py
@@ -0,0 +1,371 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, Darren Worrall <darren@iweb.co.uk>
+# Copyright (c) 2015, 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: cs_loadbalancer_rule
+short_description: Manages load balancer rules on Apache CloudStack based clouds.
+description:
+ - Add, update and remove load balancer rules.
+author:
+ - Darren Worrall (@dazworrall)
+ - René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - The name of the load balancer rule.
+ type: str
+ required: true
+ description:
+ description:
+ - The description of the load balancer rule.
+ type: str
+ algorithm:
+ description:
+ - Load balancer algorithm
+ - Required when using I(state=present).
+ type: str
+ choices: [ source, roundrobin, leastconn ]
+ default: source
+ private_port:
+ description:
+ - The private port of the private ip address/virtual machine where the network traffic will be load balanced to.
+ - Required when using I(state=present).
+ - Can not be changed once the rule exists due API limitation.
+ type: int
+ public_port:
+ description:
+ - The public port from where the network traffic will be load balanced from.
+ - Required when using I(state=present).
+ - Can not be changed once the rule exists due API limitation.
+ type: int
+ ip_address:
+ description:
+ - Public IP address from where the network traffic will be load balanced from.
+ type: str
+ required: true
+ aliases: [ public_ip ]
+ open_firewall:
+ description:
+ - Whether the firewall rule for public port should be created, while creating the new rule.
+ - Use M(cs_firewall) for managing firewall rules.
+ type: bool
+ default: no
+ cidr:
+ description:
+ - CIDR (full notation) to be used for firewall rule if required.
+ type: str
+ protocol:
+ description:
+ - The protocol to be used on the load balancer
+ type: str
+ project:
+ description:
+ - Name of the project the load balancer IP address is related to.
+ type: str
+ state:
+ description:
+ - State of the rule.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ domain:
+ description:
+ - Domain the rule is related to.
+ type: str
+ account:
+ description:
+ - Account the rule is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the rule should be created.
+ - If not set, default zone is used.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "To delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+ network:
+ description:
+ - Name of the network.
+ type: str
+ vpc:
+ description:
+ - Name of the VPC.
+ type: str
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a load balancer rule
+ ngine_io.cloudstack.cs_loadbalancer_rule:
+ name: balance_http
+ public_ip: 1.2.3.4
+ algorithm: leastconn
+ public_port: 80
+ private_port: 8080
+
+- name: Update algorithm of an existing load balancer rule
+ ngine_io.cloudstack.cs_loadbalancer_rule:
+ name: balance_http
+ public_ip: 1.2.3.4
+ algorithm: roundrobin
+ public_port: 80
+ private_port: 8080
+
+- name: Delete a load balancer rule
+ ngine_io.cloudstack.cs_loadbalancer_rule:
+ name: balance_http
+ public_ip: 1.2.3.4
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the rule.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+zone:
+ description: Name of zone the rule is related to.
+ returned: success
+ type: str
+ sample: ch-gva-2
+project:
+ description: Name of project the rule is related to.
+ returned: success
+ type: str
+ sample: Production
+account:
+ description: Account the rule is related to.
+ returned: success
+ type: str
+ sample: example account
+domain:
+ description: Domain the rule is related to.
+ returned: success
+ type: str
+ sample: example domain
+algorithm:
+ description: Load balancer algorithm used.
+ returned: success
+ type: str
+ sample: source
+cidr:
+ description: CIDR to forward traffic from.
+ returned: success
+ type: str
+ sample: 0.0.0.0/0
+name:
+ description: Name of the rule.
+ returned: success
+ type: str
+ sample: http-lb
+description:
+ description: Description of the rule.
+ returned: success
+ type: str
+ sample: http load balancer rule
+protocol:
+ description: Protocol of the rule.
+ returned: success
+ type: str
+ sample: tcp
+public_port:
+ description: Public port.
+ returned: success
+ type: int
+ sample: 80
+private_port:
+ description: Private IP address.
+ returned: success
+ type: int
+ sample: 80
+public_ip:
+ description: Public IP address.
+ returned: success
+ type: str
+ sample: 1.2.3.4
+tags:
+ description: List of resource tags associated with the rule.
+ returned: success
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+state:
+ description: State of the rule.
+ returned: success
+ type: str
+ sample: Add
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackLBRule(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackLBRule, self).__init__(module)
+ self.returns = {
+ 'publicip': 'public_ip',
+ 'algorithm': 'algorithm',
+ 'cidrlist': 'cidr',
+ 'protocol': 'protocol',
+ }
+ # these values will be casted to int
+ self.returns_to_int = {
+ 'publicport': 'public_port',
+ 'privateport': 'private_port',
+ }
+
+ def get_rule(self, **kwargs):
+ rules = self.query_api('listLoadBalancerRules', **kwargs)
+ if rules:
+ return rules['loadbalancerrule'][0]
+
+ def _get_common_args(self):
+ return {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id') if self.module.params.get('zone') else None,
+ 'publicipid': self.get_ip_address(key='id'),
+ 'name': self.module.params.get('name'),
+ }
+
+ def present_lb_rule(self):
+ required_params = [
+ 'algorithm',
+ 'private_port',
+ 'public_port',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ args = self._get_common_args()
+ rule = self.get_rule(**args)
+ if rule:
+ rule = self._update_lb_rule(rule)
+ else:
+ rule = self._create_lb_rule(rule)
+
+ if rule:
+ rule = self.ensure_tags(resource=rule, resource_type='LoadBalancer')
+ return rule
+
+ def _create_lb_rule(self, rule):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ args = self._get_common_args()
+ args.update({
+ 'algorithm': self.module.params.get('algorithm'),
+ 'privateport': self.module.params.get('private_port'),
+ 'publicport': self.module.params.get('public_port'),
+ 'cidrlist': self.module.params.get('cidr'),
+ 'description': self.module.params.get('description'),
+ 'protocol': self.module.params.get('protocol'),
+ 'networkid': self.get_network(key='id'),
+ })
+ res = self.query_api('createLoadBalancerRule', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ rule = self.poll_job(res, 'loadbalancer')
+ return rule
+
+ def _update_lb_rule(self, rule):
+ args = {
+ 'id': rule['id'],
+ 'algorithm': self.module.params.get('algorithm'),
+ 'description': self.module.params.get('description'),
+ }
+ if self.has_changed(args, rule):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateLoadBalancerRule', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ rule = self.poll_job(res, 'loadbalancer')
+ return rule
+
+ def absent_lb_rule(self):
+ args = self._get_common_args()
+ rule = self.get_rule(**args)
+ if rule:
+ self.result['changed'] = True
+ if rule and not self.module.check_mode:
+ res = self.query_api('deleteLoadBalancerRule', id=rule['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'loadbalancer')
+ return rule
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ description=dict(),
+ algorithm=dict(choices=['source', 'roundrobin', 'leastconn'], default='source'),
+ private_port=dict(type='int'),
+ public_port=dict(type='int'),
+ protocol=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ ip_address=dict(required=True, aliases=['public_ip']),
+ cidr=dict(),
+ project=dict(),
+ open_firewall=dict(type='bool', default=False),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ zone=dict(),
+ domain=dict(),
+ account=dict(),
+ vpc=dict(),
+ network=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_lb_rule = AnsibleCloudStackLBRule(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ rule = acs_lb_rule.absent_lb_rule()
+ else:
+ rule = acs_lb_rule.present_lb_rule()
+
+ result = acs_lb_rule.get_result(rule)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule_member.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule_member.py
new file mode 100644
index 00000000..6922bb83
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule_member.py
@@ -0,0 +1,345 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, Darren Worrall <darren@iweb.co.uk>
+# Copyright (c) 2015, 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: cs_loadbalancer_rule_member
+short_description: Manages load balancer rule members on Apache CloudStack based clouds.
+description:
+ - Add and remove load balancer rule members.
+author:
+ - Darren Worrall (@dazworrall)
+ - René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - The name of the load balancer rule.
+ type: str
+ required: true
+ ip_address:
+ description:
+ - Public IP address from where the network traffic will be load balanced from.
+ - Only needed to find the rule if I(name) is not unique.
+ type: str
+ aliases: [ public_ip ]
+ vms:
+ description:
+ - List of VMs to assign to or remove from the rule.
+ type: list
+ elements: str
+ required: true
+ aliases: [ vm ]
+ state:
+ description:
+ - Should the VMs be present or absent from the rule.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ project:
+ description:
+ - Name of the project the firewall rule is related to.
+ type: str
+ domain:
+ description:
+ - Domain the rule is related to.
+ type: str
+ account:
+ description:
+ - Account the rule is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the rule should be located.
+ - If not set, default zone is used.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Add VMs to an existing load balancer
+ ngine_io.cloudstack.cs_loadbalancer_rule_member:
+ name: balance_http
+ vms:
+ - web01
+ - web02
+
+- name: Remove a VM from an existing load balancer
+ ngine_io.cloudstack.cs_loadbalancer_rule_member:
+ name: balance_http
+ vms:
+ - web01
+ - web02
+ state: absent
+
+
+# Rolling upgrade of hosts
+- hosts: webservers
+ serial: 1
+ pre_tasks:
+ - name: Remove from load balancer
+ ngine_io.cloudstack.cs_loadbalancer_rule_member:
+ name: balance_http
+ vm: "{{ ansible_hostname }}"
+ state: absent
+ tasks:
+ # Perform update
+ post_tasks:
+ - name: Add to load balancer
+ ngine_io.cloudstack.cs_loadbalancer_rule_member:
+ name: balance_http
+ vm: "{{ ansible_hostname }}"
+ state: present
+
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the rule.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+zone:
+ description: Name of zone the rule is related to.
+ returned: success
+ type: str
+ sample: ch-gva-2
+project:
+ description: Name of project the rule is related to.
+ returned: success
+ type: str
+ sample: Production
+account:
+ description: Account the rule is related to.
+ returned: success
+ type: str
+ sample: example account
+domain:
+ description: Domain the rule is related to.
+ returned: success
+ type: str
+ sample: example domain
+algorithm:
+ description: Load balancer algorithm used.
+ returned: success
+ type: str
+ sample: source
+cidr:
+ description: CIDR to forward traffic from.
+ returned: success
+ type: str
+ sample: 0.0.0.0/0
+name:
+ description: Name of the rule.
+ returned: success
+ type: str
+ sample: http-lb
+description:
+ description: Description of the rule.
+ returned: success
+ type: str
+ sample: http load balancer rule
+protocol:
+ description: Protocol of the rule.
+ returned: success
+ type: str
+ sample: tcp
+public_port:
+ description: Public port.
+ returned: success
+ type: int
+ sample: 80
+private_port:
+ description: Private IP address.
+ returned: success
+ type: int
+ sample: 80
+public_ip:
+ description: Public IP address.
+ returned: success
+ type: str
+ sample: 1.2.3.4
+vms:
+ description: Rule members.
+ returned: success
+ type: list
+ sample: '[ "web01", "web02" ]'
+tags:
+ description: List of resource tags associated with the rule.
+ returned: success
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+state:
+ description: State of the rule.
+ returned: success
+ type: str
+ sample: Add
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackLBRuleMember(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackLBRuleMember, self).__init__(module)
+ self.returns = {
+ 'publicip': 'public_ip',
+ 'algorithm': 'algorithm',
+ 'cidrlist': 'cidr',
+ 'protocol': 'protocol',
+ }
+ # these values will be casted to int
+ self.returns_to_int = {
+ 'publicport': 'public_port',
+ 'privateport': 'private_port',
+ }
+
+ def get_rule(self):
+ args = self._get_common_args()
+ args.update({
+ 'name': self.module.params.get('name'),
+ 'zoneid': self.get_zone(key='id') if self.module.params.get('zone') else None,
+ })
+ if self.module.params.get('ip_address'):
+ args['publicipid'] = self.get_ip_address(key='id')
+
+ rules = self.query_api('listLoadBalancerRules', **args)
+ if rules:
+ if len(rules['loadbalancerrule']) > 1:
+ self.module.fail_json(msg="More than one rule having name %s. Please pass 'ip_address' as well." % args['name'])
+ return rules['loadbalancerrule'][0]
+ return None
+
+ def _get_common_args(self):
+ return {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ }
+
+ def _get_members_of_rule(self, rule):
+ res = self.query_api('listLoadBalancerRuleInstances', id=rule['id'])
+ return res.get('loadbalancerruleinstance', [])
+
+ def _ensure_members(self, operation):
+ if operation not in ['add', 'remove']:
+ self.module.fail_json(msg="Bad operation: %s" % operation)
+
+ rule = self.get_rule()
+ if not rule:
+ self.module.fail_json(msg="Unknown rule: %s" % self.module.params.get('name'))
+
+ existing = {}
+ for vm in self._get_members_of_rule(rule=rule):
+ existing[vm['name']] = vm['id']
+
+ wanted_names = self.module.params.get('vms')
+
+ if operation == 'add':
+ cs_func = 'assignToLoadBalancerRule'
+ to_change = set(wanted_names) - set(existing.keys())
+ else:
+ cs_func = 'removeFromLoadBalancerRule'
+ to_change = set(wanted_names) & set(existing.keys())
+
+ if not to_change:
+ return rule
+
+ args = self._get_common_args()
+ args['fetch_list'] = True
+ vms = self.query_api('listVirtualMachines', **args)
+ to_change_ids = []
+ for name in to_change:
+ for vm in vms:
+ if vm['name'] == name:
+ to_change_ids.append(vm['id'])
+ break
+ else:
+ self.module.fail_json(msg="Unknown VM: %s" % name)
+
+ if to_change_ids:
+ self.result['changed'] = True
+
+ if to_change_ids and not self.module.check_mode:
+ res = self.query_api(
+ cs_func,
+ id=rule['id'],
+ virtualmachineids=to_change_ids,
+ )
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res)
+ rule = self.get_rule()
+ return rule
+
+ def add_members(self):
+ return self._ensure_members('add')
+
+ def remove_members(self):
+ return self._ensure_members('remove')
+
+ def get_result(self, rule):
+ super(AnsibleCloudStackLBRuleMember, self).get_result(rule)
+ if rule:
+ self.result['vms'] = []
+ for vm in self._get_members_of_rule(rule=rule):
+ self.result['vms'].append(vm['name'])
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ ip_address=dict(aliases=['public_ip']),
+ vms=dict(required=True, aliases=['vm'], type='list', elements='str'),
+ state=dict(choices=['present', 'absent'], default='present'),
+ zone=dict(),
+ domain=dict(),
+ project=dict(),
+ account=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_lb_rule_member = AnsibleCloudStackLBRuleMember(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ rule = acs_lb_rule_member.remove_members()
+ else:
+ rule = acs_lb_rule_member.add_members()
+
+ result = acs_lb_rule_member.get_result(rule)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network.py
new file mode 100644
index 00000000..3dc37999
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network.py
@@ -0,0 +1,633 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, 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: cs_network
+short_description: Manages networks on Apache CloudStack based clouds.
+description:
+ - Create, update, restart and delete networks.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name (case sensitive) of the network.
+ type: str
+ required: true
+ display_text:
+ description:
+ - Display text of the network.
+ - If not specified, I(name) will be used as I(display_text).
+ type: str
+ network_offering:
+ description:
+ - Name of the offering for the network.
+ - Required if I(state=present).
+ type: str
+ start_ip:
+ description:
+ - The beginning IPv4 address of the network belongs to.
+ - Only considered on create.
+ type: str
+ end_ip:
+ description:
+ - The ending IPv4 address of the network belongs to.
+ - If not specified, value of I(start_ip) is used.
+ - Only considered on create.
+ type: str
+ gateway:
+ description:
+ - The gateway of the network.
+ - Required for shared networks and isolated networks when it belongs to a VPC.
+ - Only considered on create.
+ type: str
+ netmask:
+ description:
+ - The netmask of the network.
+ - Required for shared networks and isolated networks when it belongs to a VPC.
+ - Only considered on create.
+ type: str
+ start_ipv6:
+ description:
+ - The beginning IPv6 address of the network belongs to.
+ - Only considered on create.
+ type: str
+ end_ipv6:
+ description:
+ - The ending IPv6 address of the network belongs to.
+ - If not specified, value of I(start_ipv6) is used.
+ - Only considered on create.
+ type: str
+ cidr_ipv6:
+ description:
+ - CIDR of IPv6 network, must be at least /64.
+ - Only considered on create.
+ type: str
+ gateway_ipv6:
+ description:
+ - The gateway of the IPv6 network.
+ - Required for shared networks.
+ - Only considered on create.
+ type: str
+ vlan:
+ description:
+ - The ID or VID of the network.
+ type: str
+ vpc:
+ description:
+ - Name of the VPC of the network.
+ type: str
+ isolated_pvlan:
+ description:
+ - The isolated private VLAN for this network.
+ type: str
+ clean_up:
+ description:
+ - Cleanup old network elements.
+ - Only considered on I(state=restarted).
+ default: no
+ type: bool
+ acl_type:
+ description:
+ - Access control type for the network.
+ - If not specified, Cloudstack will default to C(account) for isolated networks
+ - and C(domain) for shared networks.
+ - Only considered on create.
+ type: str
+ choices: [ account, domain ]
+ acl:
+ description:
+ - The name of the access control list for the VPC network tier.
+ type: str
+ subdomain_access:
+ description:
+ - Defines whether to allow subdomains to use networks dedicated to their parent domain(s).
+ - Should be used with I(acl_type=domain).
+ - Only considered on create.
+ type: bool
+ network_domain:
+ description:
+ - The network domain.
+ type: str
+ state:
+ description:
+ - State of the network.
+ type: str
+ default: present
+ choices: [ present, absent, restarted ]
+ zone:
+ description:
+ - Name of the zone in which the network should be deployed.
+ - If not set, default zone is used.
+ type: str
+ project:
+ description:
+ - Name of the project the network to be deployed in.
+ type: str
+ domain:
+ description:
+ - Domain the network is related to.
+ type: str
+ account:
+ description:
+ - Account the network is related to.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "To delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a network
+ ngine_io.cloudstack.cs_network:
+ name: my network
+ zone: gva-01
+ network_offering: DefaultIsolatedNetworkOfferingWithSourceNatService
+ network_domain: example.com
+
+- name: Create a network with start and end IP
+ ngine_io.cloudstack.cs_network:
+ name: Private Network
+ network_offering: PrivNet
+ start_ip: 10.12.9.10
+ end_ip: 10.12.9.100
+ netmask: 255.255.255.0
+ zone: gva-01
+
+- name: Create a VPC tier
+ ngine_io.cloudstack.cs_network:
+ name: my VPC tier 1
+ zone: gva-01
+ vpc: my VPC
+ network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks
+ gateway: 10.43.0.1
+ netmask: 255.255.255.0
+ acl: my web acl
+
+- name: Update a network
+ ngine_io.cloudstack.cs_network:
+ name: my network
+ display_text: network of domain example.local
+ network_domain: example.local
+
+- name: Restart a network with clean up
+ ngine_io.cloudstack.cs_network:
+ name: my network
+ clean_up: yes
+ state: restarted
+
+- name: Remove a network
+ ngine_io.cloudstack.cs_network:
+ name: my network
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the network.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: Name of the network.
+ returned: success
+ type: str
+ sample: web project
+display_text:
+ description: Display text of the network.
+ returned: success
+ type: str
+ sample: web project
+dns1:
+ description: IP address of the 1st nameserver.
+ returned: success
+ type: str
+ sample: 1.2.3.4
+dns2:
+ description: IP address of the 2nd nameserver.
+ returned: success
+ type: str
+ sample: 1.2.3.4
+cidr:
+ description: IPv4 network CIDR.
+ returned: success
+ type: str
+ sample: 10.101.64.0/24
+gateway:
+ description: IPv4 gateway.
+ returned: success
+ type: str
+ sample: 10.101.64.1
+netmask:
+ description: IPv4 netmask.
+ returned: success
+ type: str
+ sample: 255.255.255.0
+cidr_ipv6:
+ description: IPv6 network CIDR.
+ returned: if available
+ type: str
+ sample: 2001:db8::/64
+gateway_ipv6:
+ description: IPv6 gateway.
+ returned: if available
+ type: str
+ sample: 2001:db8::1
+zone:
+ description: Name of zone.
+ returned: success
+ type: str
+ sample: ch-gva-2
+domain:
+ description: Domain the network is related to.
+ returned: success
+ type: str
+ sample: ROOT
+account:
+ description: Account the network is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project.
+ returned: success
+ type: str
+ sample: Production
+tags:
+ description: List of resource tags associated with the network.
+ returned: success
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+acl_type:
+ description: Access type of the network (Domain, Account).
+ returned: success
+ type: str
+ sample: Account
+acl:
+ description: Name of the access control list for the VPC network tier.
+ returned: success
+ type: str
+ sample: My ACL
+acl_id:
+ description: ID of the access control list for the VPC network tier.
+ returned: success
+ type: str
+ sample: dfafcd55-0510-4b8c-b6c5-b8cedb4cfd88
+broadcast_domain_type:
+ description: Broadcast domain type of the network.
+ returned: success
+ type: str
+ sample: Vlan
+type:
+ description: Type of the network.
+ returned: success
+ type: str
+ sample: Isolated
+traffic_type:
+ description: Traffic type of the network.
+ returned: success
+ type: str
+ sample: Guest
+state:
+ description: State of the network (Allocated, Implemented, Setup).
+ returned: success
+ type: str
+ sample: Allocated
+is_persistent:
+ description: Whether the network is persistent or not.
+ returned: success
+ type: bool
+ sample: false
+network_domain:
+ description: The network domain
+ returned: success
+ type: str
+ sample: example.local
+network_offering:
+ description: The network offering name.
+ returned: success
+ type: str
+ sample: DefaultIsolatedNetworkOfferingWithSourceNatService
+network_offering_display_text:
+ description: The network offering display text.
+ returned: success
+ type: str
+ sample: Offering for Isolated Vpc networks with Source Nat service enabled
+network_offering_conserve_mode:
+ description: Whether the network offering has IP conserve mode enabled or not.
+ returned: success
+ type: bool
+ sample: false
+network_offering_availability:
+ description: The availability of the network offering the network is created from
+ returned: success
+ type: str
+ sample: Optional
+is_system:
+ description: Whether the network is system related or not.
+ returned: success
+ type: bool
+ sample: false
+vpc:
+ description: Name of the VPC.
+ returned: if available
+ type: str
+ sample: My VPC
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackNetwork(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackNetwork, self).__init__(module)
+ self.returns = {
+ 'networkdomain': 'network_domain',
+ 'networkofferingname': 'network_offering',
+ 'networkofferingdisplaytext': 'network_offering_display_text',
+ 'networkofferingconservemode': 'network_offering_conserve_mode',
+ 'networkofferingavailability': 'network_offering_availability',
+ 'aclid': 'acl_id',
+ 'issystem': 'is_system',
+ 'ispersistent': 'is_persistent',
+ 'acltype': 'acl_type',
+ 'type': 'type',
+ 'traffictype': 'traffic_type',
+ 'ip6gateway': 'gateway_ipv6',
+ 'ip6cidr': 'cidr_ipv6',
+ 'gateway': 'gateway',
+ 'cidr': 'cidr',
+ 'netmask': 'netmask',
+ 'broadcastdomaintype': 'broadcast_domain_type',
+ 'dns1': 'dns1',
+ 'dns2': 'dns2',
+ }
+ self.network = None
+
+ def get_network_acl(self, key=None, acl_id=None):
+ if acl_id is not None:
+ args = {
+ 'id': acl_id,
+ 'vpcid': self.get_vpc(key='id'),
+ }
+ else:
+ acl_name = self.module.params.get('acl')
+ if not acl_name:
+ return
+
+ args = {
+ 'name': acl_name,
+ 'vpcid': self.get_vpc(key='id'),
+ }
+ network_acls = self.query_api('listNetworkACLLists', **args)
+ if network_acls:
+ acl = network_acls['networkacllist'][0]
+ return self._get_by_key(key, acl)
+
+ def get_network_offering(self, key=None):
+ network_offering = self.module.params.get('network_offering')
+ if not network_offering:
+ self.module.fail_json(msg="missing required arguments: network_offering")
+
+ args = {
+ 'zoneid': self.get_zone(key='id'),
+ 'fetch_list': True,
+ }
+
+ network_offerings = self.query_api('listNetworkOfferings', **args)
+ if network_offerings:
+ for no in network_offerings:
+ if network_offering in [no['name'], no['displaytext'], no['id']]:
+ return self._get_by_key(key, no)
+ self.module.fail_json(msg="Network offering '%s' not found" % network_offering)
+
+ def _get_args(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ 'networkdomain': self.module.params.get('network_domain'),
+ 'networkofferingid': self.get_network_offering(key='id')
+ }
+ return args
+
+ def get_network(self, refresh=False):
+ if not self.network or refresh:
+ network = self.module.params.get('name')
+ args = {
+ 'zoneid': self.get_zone(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'vpcid': self.get_vpc(key='id'),
+ 'fetch_list': True,
+ }
+ networks = self.query_api('listNetworks', **args)
+ if networks:
+ for n in networks:
+ if network in [n['name'], n['displaytext'], n['id']]:
+ self.network = n
+ self.network['acl'] = self.get_network_acl(key='name', acl_id=n.get('aclid'))
+ break
+ return self.network
+
+ def present_network(self):
+ if self.module.params.get('acl') is not None and self.module.params.get('vpc') is None:
+ self.module.fail_json(msg="Missing required params: vpc")
+
+ network = self.get_network()
+ if not network:
+ network = self.create_network(network)
+ else:
+ network = self.update_network(network)
+
+ if network:
+ network = self.ensure_tags(resource=network, resource_type='Network')
+
+ return network
+
+ def update_network(self, network):
+ args = self._get_args()
+ args['id'] = network['id']
+
+ if self.has_changed(args, network):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ network = self.query_api('updateNetwork', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if network and poll_async:
+ network = self.poll_job(network, 'network')
+
+ # Skip ACL check if the network is not a VPC tier
+ if network.get('aclid') != self.get_network_acl(key='id'):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ args = {
+ 'aclid': self.get_network_acl(key='id'),
+ 'networkid': network['id'],
+ }
+ network = self.query_api('replaceNetworkACLList', **args)
+ if self.module.params.get('poll_async'):
+ self.poll_job(network, 'networkacllist')
+ network = self.get_network(refresh=True)
+ return network
+
+ def create_network(self, network):
+ self.result['changed'] = True
+
+ args = self._get_args()
+ args.update({
+ 'acltype': self.module.params.get('acl_type'),
+ 'aclid': self.get_network_acl(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'startip': self.module.params.get('start_ip'),
+ 'endip': self.get_or_fallback('end_ip', 'start_ip'),
+ 'netmask': self.module.params.get('netmask'),
+ 'gateway': self.module.params.get('gateway'),
+ 'startipv6': self.module.params.get('start_ipv6'),
+ 'endipv6': self.get_or_fallback('end_ipv6', 'start_ipv6'),
+ 'ip6cidr': self.module.params.get('cidr_ipv6'),
+ 'ip6gateway': self.module.params.get('gateway_ipv6'),
+ 'vlan': self.module.params.get('vlan'),
+ 'isolatedpvlan': self.module.params.get('isolated_pvlan'),
+ 'subdomainaccess': self.module.params.get('subdomain_access'),
+ 'vpcid': self.get_vpc(key='id')
+ })
+
+ if not self.module.check_mode:
+ res = self.query_api('createNetwork', **args)
+
+ network = res['network']
+ return network
+
+ def restart_network(self):
+ network = self.get_network()
+
+ if not network:
+ self.module.fail_json(msg="No network named '%s' found." % self.module.params('name'))
+
+ # Restarting only available for these states
+ if network['state'].lower() in ['implemented', 'setup']:
+ self.result['changed'] = True
+
+ args = {
+ 'id': network['id'],
+ 'cleanup': self.module.params.get('clean_up')
+ }
+
+ if not self.module.check_mode:
+ network = self.query_api('restartNetwork', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if network and poll_async:
+ network = self.poll_job(network, 'network')
+ return network
+
+ def absent_network(self):
+ network = self.get_network()
+ if network:
+ self.result['changed'] = True
+
+ args = {
+ 'id': network['id']
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('deleteNetwork', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ self.poll_job(res, 'network')
+ return network
+
+ def get_result(self, network):
+ super(AnsibleCloudStackNetwork, self).get_result(network)
+ if network:
+ self.result['acl'] = self.get_network_acl(key='name', acl_id=network.get('aclid'))
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ display_text=dict(),
+ network_offering=dict(),
+ zone=dict(),
+ start_ip=dict(),
+ end_ip=dict(),
+ gateway=dict(),
+ netmask=dict(),
+ start_ipv6=dict(),
+ end_ipv6=dict(),
+ cidr_ipv6=dict(),
+ gateway_ipv6=dict(),
+ vlan=dict(),
+ vpc=dict(),
+ isolated_pvlan=dict(),
+ clean_up=dict(type='bool', default=False),
+ network_domain=dict(),
+ subdomain_access=dict(type='bool'),
+ state=dict(choices=['present', 'absent', 'restarted'], default='present'),
+ acl=dict(),
+ acl_type=dict(choices=['account', 'domain']),
+ project=dict(),
+ domain=dict(),
+ account=dict(),
+ poll_async=dict(type='bool', default=True),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_network = AnsibleCloudStackNetwork(module)
+
+ state = module.params.get('state')
+ if state == 'absent':
+ network = acs_network.absent_network()
+
+ elif state == 'restarted':
+ network = acs_network.restart_network()
+
+ else:
+ network = acs_network.present_network()
+
+ result = acs_network.get_result(network)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl.py
new file mode 100644
index 00000000..b6cd0e18
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl.py
@@ -0,0 +1,197 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, 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: cs_network_acl
+short_description: Manages network access control lists (ACL) on Apache CloudStack based clouds.
+description:
+ - Create and remove network ACLs.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the network ACL.
+ type: str
+ required: true
+ description:
+ description:
+ - Description of the network ACL.
+ - If not set, identical to I(name).
+ type: str
+ vpc:
+ description:
+ - VPC the network ACL is related to.
+ type: str
+ required: true
+ state:
+ description:
+ - State of the network ACL.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ domain:
+ description:
+ - Domain the network ACL rule is related to.
+ type: str
+ account:
+ description:
+ - Account the network ACL rule is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the network ACL is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone the VPC is related to.
+ - If not set, default zone is used.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: create a network ACL
+ ngine_io.cloudstack.cs_network_acl:
+ name: Webserver ACL
+ description: a more detailed description of the ACL
+ vpc: customers
+
+- name: remove a network ACL
+ ngine_io.cloudstack.cs_network_acl:
+ name: Webserver ACL
+ vpc: customers
+ state: absent
+'''
+
+RETURN = '''
+---
+name:
+ description: Name of the network ACL.
+ returned: success
+ type: str
+ sample: customer acl
+description:
+ description: Description of the network ACL.
+ returned: success
+ type: str
+ sample: Example description of a network ACL
+vpc:
+ description: VPC of the network ACL.
+ returned: success
+ type: str
+ sample: customer vpc
+zone:
+ description: Zone the VPC is related to.
+ returned: success
+ type: str
+ sample: ch-gva-2
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackNetworkAcl(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackNetworkAcl, self).__init__(module)
+
+ def get_network_acl(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'vpcid': self.get_vpc(key='id'),
+ }
+ network_acls = self.query_api('listNetworkACLLists', **args)
+ if network_acls:
+ return network_acls['networkacllist'][0]
+ return None
+
+ def present_network_acl(self):
+ network_acl = self.get_network_acl()
+ if not network_acl:
+ self.result['changed'] = True
+ args = {
+ 'name': self.module.params.get('name'),
+ 'description': self.get_or_fallback('description', 'name'),
+ 'vpcid': self.get_vpc(key='id')
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createNetworkACLList', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ network_acl = self.poll_job(res, 'networkacllist')
+
+ return network_acl
+
+ def absent_network_acl(self):
+ network_acl = self.get_network_acl()
+ if network_acl:
+ self.result['changed'] = True
+ args = {
+ 'id': network_acl['id'],
+ }
+ if not self.module.check_mode:
+ res = self.query_api('deleteNetworkACLList', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'networkacllist')
+
+ return network_acl
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ description=dict(),
+ vpc=dict(required=True),
+ state=dict(choices=['present', 'absent'], default='present'),
+ zone=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_network_acl = AnsibleCloudStackNetworkAcl(module)
+
+ state = module.params.get('state')
+ if state == 'absent':
+ network_acl = acs_network_acl.absent_network_acl()
+ else:
+ network_acl = acs_network_acl.present_network_acl()
+
+ result = acs_network_acl.get_result(network_acl)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl_rule.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl_rule.py
new file mode 100644
index 00000000..acce9e2c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl_rule.py
@@ -0,0 +1,457 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, 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: cs_network_acl_rule
+short_description: Manages network access control list (ACL) rules on Apache CloudStack based clouds.
+description:
+ - Add, update and remove network ACL rules.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ network_acl:
+ description:
+ - Name of the network ACL.
+ type: str
+ required: true
+ aliases: [ acl ]
+ cidrs:
+ description:
+ - CIDRs of the rule.
+ type: list
+ elements: str
+ default: [ 0.0.0.0/0 ]
+ aliases: [ cidr ]
+ rule_position:
+ description:
+ - The position of the network ACL rule.
+ type: int
+ required: true
+ aliases: [ number ]
+ protocol:
+ description:
+ - Protocol of the rule
+ choices: [ tcp, udp, icmp, all, by_number ]
+ type: str
+ default: tcp
+ protocol_number:
+ description:
+ - Protocol number from 1 to 256 required if I(protocol=by_number).
+ type: int
+ start_port:
+ description:
+ - Start port for this rule.
+ - Considered if I(protocol=tcp) or I(protocol=udp).
+ type: int
+ aliases: [ port ]
+ end_port:
+ description:
+ - End port for this rule.
+ - Considered if I(protocol=tcp) or I(protocol=udp).
+ - If not specified, equal I(start_port).
+ type: int
+ icmp_type:
+ description:
+ - Type of the icmp message being sent.
+ - Considered if I(protocol=icmp).
+ type: int
+ icmp_code:
+ description:
+ - Error code for this icmp message.
+ - Considered if I(protocol=icmp).
+ type: int
+ vpc:
+ description:
+ - VPC the network ACL is related to.
+ type: str
+ required: true
+ traffic_type:
+ description:
+ - Traffic type of the rule.
+ type: str
+ choices: [ ingress, egress ]
+ default: ingress
+ aliases: [ type ]
+ action_policy:
+ description:
+ - Action policy of the rule.
+ type: str
+ choices: [ allow, deny ]
+ default: allow
+ aliases: [ action ]
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "If you want to delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+ domain:
+ description:
+ - Domain the VPC is related to.
+ type: str
+ account:
+ description:
+ - Account the VPC is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the VPC is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone the VPC related to.
+ - If not set, default zone is used.
+ type: str
+ state:
+ description:
+ - State of the network ACL rule.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: create a network ACL rule, allow port 80 ingress
+ ngine_io.cloudstack.cs_network_acl_rule:
+ network_acl: web
+ rule_position: 1
+ vpc: my vpc
+ traffic_type: ingress
+ action_policy: allow
+ port: 80
+ cidr: 0.0.0.0/0
+
+- name: create a network ACL rule, deny port range 8000-9000 ingress for 10.20.0.0/16 and 10.22.0.0/16
+ ngine_io.cloudstack.cs_network_acl_rule:
+ network_acl: web
+ rule_position: 1
+ vpc: my vpc
+ traffic_type: ingress
+ action_policy: deny
+ start_port: 8000
+ end_port: 9000
+ cidrs:
+ - 10.20.0.0/16
+ - 10.22.0.0/16
+
+- name: remove a network ACL rule
+ ngine_io.cloudstack.cs_network_acl_rule:
+ network_acl: web
+ rule_position: 1
+ vpc: my vpc
+ state: absent
+'''
+
+RETURN = '''
+---
+network_acl:
+ description: Name of the network ACL.
+ returned: success
+ type: str
+ sample: customer acl
+cidr:
+ description: CIDR of the network ACL rule.
+ returned: success
+ type: str
+ sample: 0.0.0.0/0
+cidrs:
+ description: CIDRs of the network ACL rule.
+ returned: success
+ type: list
+ sample: [ 0.0.0.0/0 ]
+rule_position:
+ description: Position of the network ACL rule.
+ returned: success
+ type: int
+ sample: 1
+action_policy:
+ description: Action policy of the network ACL rule.
+ returned: success
+ type: str
+ sample: deny
+traffic_type:
+ description: Traffic type of the network ACL rule.
+ returned: success
+ type: str
+ sample: ingress
+protocol:
+ description: Protocol of the network ACL rule.
+ returned: success
+ type: str
+ sample: tcp
+protocol_number:
+ description: Protocol number in case protocol is by number.
+ returned: success
+ type: int
+ sample: 8
+start_port:
+ description: Start port of the network ACL rule.
+ returned: success
+ type: int
+ sample: 80
+end_port:
+ description: End port of the network ACL rule.
+ returned: success
+ type: int
+ sample: 80
+icmp_code:
+ description: ICMP code of the network ACL rule.
+ returned: success
+ type: int
+ sample: 8
+icmp_type:
+ description: ICMP type of the network ACL rule.
+ returned: success
+ type: int
+ sample: 0
+state:
+ description: State of the network ACL rule.
+ returned: success
+ type: str
+ sample: Active
+vpc:
+ description: VPC of the network ACL.
+ returned: success
+ type: str
+ sample: customer vpc
+tags:
+ description: List of resource tags associated with the network ACL rule.
+ returned: success
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+domain:
+ description: Domain the network ACL rule is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the network ACL rule is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project the network ACL rule is related to.
+ returned: success
+ type: str
+ sample: Production
+zone:
+ description: Zone the VPC is related to.
+ returned: success
+ type: str
+ sample: ch-gva-2
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackNetworkAclRule(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackNetworkAclRule, self).__init__(module)
+ self.returns = {
+ 'cidrlist': 'cidr',
+ 'action': 'action_policy',
+ 'protocol': 'protocol',
+ 'icmpcode': 'icmp_code',
+ 'icmptype': 'icmp_type',
+ 'number': 'rule_position',
+ 'traffictype': 'traffic_type',
+ }
+ # these values will be casted to int
+ self.returns_to_int = {
+ 'startport': 'start_port',
+ 'endport': 'end_port',
+ }
+
+ def get_network_acl_rule(self):
+ args = {
+ 'aclid': self.get_network_acl(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ }
+ network_acl_rules = self.query_api('listNetworkACLs', **args)
+ for acl_rule in network_acl_rules.get('networkacl', []):
+ if acl_rule['number'] == self.module.params.get('rule_position'):
+ return acl_rule
+ return None
+
+ def present_network_acl_rule(self):
+ network_acl_rule = self.get_network_acl_rule()
+
+ protocol = self.module.params.get('protocol')
+ start_port = self.module.params.get('start_port')
+ end_port = self.get_or_fallback('end_port', 'start_port')
+ icmp_type = self.module.params.get('icmp_type')
+ icmp_code = self.module.params.get('icmp_code')
+
+ if protocol in ['tcp', 'udp'] and (start_port is None or end_port is None):
+ self.module.fail_json(msg="protocol is %s but the following are missing: start_port, end_port" % protocol)
+
+ elif protocol == 'icmp' and (icmp_type is None or icmp_code is None):
+ self.module.fail_json(msg="protocol is icmp but the following are missing: icmp_type, icmp_code")
+
+ elif protocol == 'by_number' and self.module.params.get('protocol_number') is None:
+ self.module.fail_json(msg="protocol is by_number but the following are missing: protocol_number")
+
+ if not network_acl_rule:
+ network_acl_rule = self._create_network_acl_rule(network_acl_rule)
+ else:
+ network_acl_rule = self._update_network_acl_rule(network_acl_rule)
+
+ if network_acl_rule:
+ network_acl_rule = self.ensure_tags(resource=network_acl_rule, resource_type='NetworkACL')
+ return network_acl_rule
+
+ def absent_network_acl_rule(self):
+ network_acl_rule = self.get_network_acl_rule()
+ if network_acl_rule:
+ self.result['changed'] = True
+ args = {
+ 'id': network_acl_rule['id'],
+ }
+ if not self.module.check_mode:
+ res = self.query_api('deleteNetworkACL', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'networkacl')
+
+ return network_acl_rule
+
+ def _create_network_acl_rule(self, network_acl_rule):
+ self.result['changed'] = True
+ protocol = self.module.params.get('protocol')
+ args = {
+ 'aclid': self.get_network_acl(key='id'),
+ 'action': self.module.params.get('action_policy'),
+ 'protocol': protocol if protocol != 'by_number' else self.module.params.get('protocol_number'),
+ 'startport': self.module.params.get('start_port'),
+ 'endport': self.get_or_fallback('end_port', 'start_port'),
+ 'number': self.module.params.get('rule_position'),
+ 'icmpcode': self.module.params.get('icmp_code'),
+ 'icmptype': self.module.params.get('icmp_type'),
+ 'traffictype': self.module.params.get('traffic_type'),
+ 'cidrlist': self.module.params.get('cidrs'),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createNetworkACL', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ network_acl_rule = self.poll_job(res, 'networkacl')
+
+ return network_acl_rule
+
+ def _update_network_acl_rule(self, network_acl_rule):
+ protocol = self.module.params.get('protocol')
+ args = {
+ 'id': network_acl_rule['id'],
+ 'action': self.module.params.get('action_policy'),
+ 'protocol': protocol if protocol != 'by_number' else str(self.module.params.get('protocol_number')),
+ 'startport': self.module.params.get('start_port'),
+ 'endport': self.get_or_fallback('end_port', 'start_port'),
+ 'icmpcode': self.module.params.get('icmp_code'),
+ 'icmptype': self.module.params.get('icmp_type'),
+ 'traffictype': self.module.params.get('traffic_type'),
+ 'cidrlist': ",".join(self.module.params.get('cidrs')),
+ }
+ if self.has_changed(args, network_acl_rule):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateNetworkACLItem', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ network_acl_rule = self.poll_job(res, 'networkacl')
+
+ return network_acl_rule
+
+ def get_result(self, network_acl_rule):
+ super(AnsibleCloudStackNetworkAclRule, self).get_result(network_acl_rule)
+ if network_acl_rule:
+ if 'cidrlist' in network_acl_rule:
+ self.result['cidrs'] = network_acl_rule['cidrlist'].split(',') or [network_acl_rule['cidrlist']]
+ if network_acl_rule['protocol'] not in ['tcp', 'udp', 'icmp', 'all']:
+ self.result['protocol_number'] = int(network_acl_rule['protocol'])
+ self.result['protocol'] = 'by_number'
+ self.result['action_policy'] = self.result['action_policy'].lower()
+ self.result['traffic_type'] = self.result['traffic_type'].lower()
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ network_acl=dict(required=True, aliases=['acl']),
+ rule_position=dict(required=True, type='int', aliases=['number']),
+ vpc=dict(required=True),
+ cidrs=dict(type='list', elements='str', default=['0.0.0.0/0'], aliases=['cidr']),
+ protocol=dict(choices=['tcp', 'udp', 'icmp', 'all', 'by_number'], default='tcp'),
+ protocol_number=dict(type='int'),
+ traffic_type=dict(choices=['ingress', 'egress'], aliases=['type'], default='ingress'),
+ action_policy=dict(choices=['allow', 'deny'], aliases=['action'], default='allow'),
+ icmp_type=dict(type='int'),
+ icmp_code=dict(type='int'),
+ start_port=dict(type='int', aliases=['port']),
+ end_port=dict(type='int'),
+ state=dict(choices=['present', 'absent'], default='present'),
+ zone=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ required_together = cs_required_together()
+ required_together.extend([
+ ['icmp_type', 'icmp_code'],
+ ])
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ mutually_exclusive=(
+ ['icmp_type', 'start_port'],
+ ['icmp_type', 'end_port'],
+ ),
+ supports_check_mode=True
+ )
+
+ acs_network_acl_rule = AnsibleCloudStackNetworkAclRule(module)
+
+ state = module.params.get('state')
+ if state == 'absent':
+ network_acl_rule = acs_network_acl_rule.absent_network_acl_rule()
+ else:
+ network_acl_rule = acs_network_acl_rule.present_network_acl_rule()
+
+ result = acs_network_acl_rule.get_result(network_acl_rule)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_offering.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_offering.py
new file mode 100644
index 00000000..a5c5cb93
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_offering.py
@@ -0,0 +1,422 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, David Passante (@dpassante)
+# Copyright (c) 2017, 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: cs_network_offering
+short_description: Manages network offerings on Apache CloudStack based clouds.
+description:
+ - Create, update, enable, disable and remove network offerings.
+author: David Passante (@dpassante)
+version_added: 0.1.0
+options:
+ state:
+ description:
+ - State of the network offering.
+ type: str
+ choices: [ enabled, present, disabled, absent]
+ default: present
+ display_text:
+ description:
+ - Display text of the network offerings.
+ type: str
+ guest_ip_type:
+ description:
+ - Guest type of the network offering.
+ type: str
+ choices: [ Shared, Isolated ]
+ name:
+ description:
+ - The name of the network offering.
+ type: str
+ required: true
+ supported_services:
+ description:
+ - Services supported by the network offering.
+ - A list of one or more items from the choice list.
+ type: list
+ elements: str
+ choices: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ aliases: [ supported_service ]
+ traffic_type:
+ description:
+ - The traffic type for the network offering.
+ type: str
+ default: Guest
+ availability:
+ description:
+ - The availability of network offering. Default value is Optional
+ type: str
+ conserve_mode:
+ description:
+ - Whether the network offering has IP conserve mode enabled.
+ type: bool
+ details:
+ description:
+ - Network offering details in key/value pairs.
+ - with service provider as a value
+ type: list
+ elements: dict
+ egress_default_policy:
+ description:
+ - Whether the default egress policy is allow or to deny.
+ type: str
+ choices: [ allow, deny ]
+ persistent:
+ description:
+ - True if network offering supports persistent networks
+ - defaulted to false if not specified
+ type: bool
+ keepalive_enabled:
+ description:
+ - If true keepalive will be turned on in the loadbalancer.
+ - At the time of writing this has only an effect on haproxy.
+ - the mode http and httpclose options are unset in the haproxy conf file.
+ type: bool
+ max_connections:
+ description:
+ - Maximum number of concurrent connections supported by the network offering.
+ type: int
+ network_rate:
+ description:
+ - Data transfer rate in megabits per second allowed.
+ type: int
+ service_capabilities:
+ description:
+ - Desired service capabilities as part of network offering.
+ type: list
+ elements: str
+ aliases: [ service_capability ]
+ service_offering:
+ description:
+ - The service offering name or ID used by virtual router provider.
+ type: str
+ service_providers:
+ description:
+ - Provider to service mapping.
+ - If not specified, the provider for the service will be mapped to the default provider on the physical network.
+ type: list
+ elements: dict
+ aliases: [ service_provider ]
+ specify_ip_ranges:
+ description:
+ - Whether the network offering supports specifying IP ranges.
+ - Defaulted to C(no) by the API if not specified.
+ type: bool
+ specify_vlan:
+ description:
+ - Whether the network offering supports vlans or not.
+ type: bool
+ for_vpc:
+ description:
+ - Whether the offering is meant to be used for VPC or not.
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a network offering and enable it
+ ngine_io.cloudstack.cs_network_offering:
+ name: my_network_offering
+ display_text: network offering description
+ state: enabled
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+
+- name: Remove a network offering
+ ngine_io.cloudstack.cs_network_offering:
+ name: my_network_offering
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the network offering.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+name:
+ description: The name of the network offering.
+ returned: success
+ type: str
+ sample: MyCustomNetworkOffering
+display_text:
+ description: The display text of the network offering.
+ returned: success
+ type: str
+ sample: My network offering
+state:
+ description: The state of the network offering.
+ returned: success
+ type: str
+ sample: Enabled
+guest_ip_type:
+ description: Guest type of the network offering.
+ returned: success
+ type: str
+ sample: Isolated
+availability:
+ description: The availability of network offering.
+ returned: success
+ type: str
+ sample: Optional
+service_offering_id:
+ description: The service offering ID.
+ returned: success
+ type: str
+ sample: c5f7a5fc-43f8-11e5-a151-feff819cdc9f
+max_connections:
+ description: The maximum number of concurrent connections to be handled by LB.
+ returned: success
+ type: int
+ sample: 300
+network_rate:
+ description: The network traffic transfer ate in Mbit/s.
+ returned: success
+ type: int
+ sample: 200
+traffic_type:
+ description: The traffic type.
+ returned: success
+ type: str
+ sample: Guest
+egress_default_policy:
+ description: Default egress policy.
+ returned: success
+ type: str
+ sample: allow
+is_persistent:
+ description: Whether persistent networks are supported or not.
+ returned: success
+ type: bool
+ sample: false
+is_default:
+ description: Whether network offering is the default offering or not.
+ returned: success
+ type: bool
+ sample: false
+for_vpc:
+ description: Whether the offering is meant to be used for VPC or not.
+ returned: success
+ type: bool
+ sample: false
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackNetworkOffering(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackNetworkOffering, self).__init__(module)
+ self.returns = {
+ 'guestiptype': 'guest_ip_type',
+ 'availability': 'availability',
+ 'serviceofferingid': 'service_offering_id',
+ 'networkrate': 'network_rate',
+ 'maxconnections': 'max_connections',
+ 'traffictype': 'traffic_type',
+ 'isdefault': 'is_default',
+ 'ispersistent': 'is_persistent',
+ 'forvpc': 'for_vpc'
+ }
+ self.network_offering = None
+
+ def get_service_offering_id(self):
+ service_offering = self.module.params.get('service_offering')
+ if not service_offering:
+ return None
+
+ args = {
+ 'issystem': True
+ }
+
+ service_offerings = self.query_api('listServiceOfferings', **args)
+ if service_offerings:
+ for s in service_offerings['serviceoffering']:
+ if service_offering in [s['name'], s['id']]:
+ return s['id']
+ self.fail_json(msg="Service offering '%s' not found" % service_offering)
+
+ def get_network_offering(self):
+ if self.network_offering:
+ return self.network_offering
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'guestiptype': self.module.params.get('guest_type'),
+ }
+ no = self.query_api('listNetworkOfferings', **args)
+ if no:
+ self.network_offering = no['networkoffering'][0]
+
+ return self.network_offering
+
+ def create_or_update(self):
+ network_offering = self.get_network_offering()
+
+ if not network_offering:
+ network_offering = self.create_network_offering()
+
+ return self.update_network_offering(network_offering=network_offering)
+
+ def create_network_offering(self):
+ network_offering = None
+ self.result['changed'] = True
+
+ args = {
+ 'state': self.module.params.get('state'),
+ 'displaytext': self.module.params.get('display_text'),
+ 'guestiptype': self.module.params.get('guest_ip_type'),
+ 'name': self.module.params.get('name'),
+ 'supportedservices': self.module.params.get('supported_services'),
+ 'traffictype': self.module.params.get('traffic_type'),
+ 'availability': self.module.params.get('availability'),
+ 'conservemode': self.module.params.get('conserve_mode'),
+ 'details': self.module.params.get('details'),
+ 'egressdefaultpolicy': self.module.params.get('egress_default_policy') == 'allow',
+ 'ispersistent': self.module.params.get('persistent'),
+ 'keepaliveenabled': self.module.params.get('keepalive_enabled'),
+ 'maxconnections': self.module.params.get('max_connections'),
+ 'networkrate': self.module.params.get('network_rate'),
+ 'servicecapabilitylist': self.module.params.get('service_capabilities'),
+ 'serviceofferingid': self.get_service_offering_id(),
+ 'serviceproviderlist': self.module.params.get('service_providers'),
+ 'specifyipranges': self.module.params.get('specify_ip_ranges'),
+ 'specifyvlan': self.module.params.get('specify_vlan'),
+ 'forvpc': self.module.params.get('for_vpc'),
+ }
+
+ required_params = [
+ 'display_text',
+ 'guest_ip_type',
+ 'supported_services',
+ 'service_providers',
+ ]
+
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ if not self.module.check_mode:
+ res = self.query_api('createNetworkOffering', **args)
+ network_offering = res['networkoffering']
+
+ return network_offering
+
+ def delete_network_offering(self):
+ network_offering = self.get_network_offering()
+
+ if network_offering:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ self.query_api('deleteNetworkOffering', id=network_offering['id'])
+
+ return network_offering
+
+ def update_network_offering(self, network_offering):
+ if not network_offering:
+ return network_offering
+
+ args = {
+ 'id': network_offering['id'],
+ 'state': self.module.params.get('state'),
+ 'displaytext': self.module.params.get('display_text'),
+ 'name': self.module.params.get('name'),
+ 'availability': self.module.params.get('availability'),
+ 'maxconnections': self.module.params.get('max_connections'),
+ }
+
+ if args['state'] in ['enabled', 'disabled']:
+ args['state'] = args['state'].title()
+ else:
+ del args['state']
+
+ if self.has_changed(args, network_offering):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('updateNetworkOffering', **args)
+ network_offering = res['networkoffering']
+
+ return network_offering
+
+ def get_result(self, network_offering):
+ super(AnsibleCloudStackNetworkOffering, self).get_result(network_offering)
+ if network_offering:
+ self.result['egress_default_policy'] = 'allow' if network_offering.get('egressdefaultpolicy') else 'deny'
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ state=dict(choices=['enabled', 'present', 'disabled', 'absent'], default='present'),
+ display_text=dict(),
+ guest_ip_type=dict(choices=['Shared', 'Isolated']),
+ name=dict(required=True),
+ supported_services=dict(type='list', elements='str', aliases=['supported_service'], choices=[
+ 'Dns',
+ 'PortForwarding',
+ 'Dhcp',
+ 'SourceNat',
+ 'UserData',
+ 'Firewall',
+ 'StaticNat',
+ 'Vpn',
+ 'Lb',
+ ]),
+ traffic_type=dict(default='Guest'),
+ availability=dict(),
+ conserve_mode=dict(type='bool'),
+ details=dict(type='list', elements='dict'),
+ egress_default_policy=dict(choices=['allow', 'deny']),
+ persistent=dict(type='bool'),
+ keepalive_enabled=dict(type='bool'),
+ max_connections=dict(type='int'),
+ network_rate=dict(type='int'),
+ service_capabilities=dict(type='list', elements='str', aliases=['service_capability']),
+ service_offering=dict(),
+ service_providers=dict(type='list', elements='dict', aliases=['service_provider']),
+ specify_ip_ranges=dict(type='bool'),
+ specify_vlan=dict(type='bool'),
+ for_vpc=dict(type='bool'),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_network_offering = AnsibleCloudStackNetworkOffering(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ network_offering = acs_network_offering.delete_network_offering()
+ else:
+ network_offering = acs_network_offering.create_or_update()
+
+ result = acs_network_offering.get_result(network_offering)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_physical_network.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_physical_network.py
new file mode 100644
index 00000000..2148afc2
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_physical_network.py
@@ -0,0 +1,473 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, Netservers Ltd. <support@netservers.co.uk>
+# 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: cs_physical_network
+short_description: Manages physical networks on Apache CloudStack based clouds.
+description:
+ - Create, update and remove networks.
+ - Enabled and disabled Network Service Providers
+ - Enables Internal LoadBalancer and VPC/VirtualRouter elements as required
+author:
+ - Netservers Ltd. (@netservers)
+ - Patryk Cichy (@PatTheSilent)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the physical network.
+ required: true
+ aliases:
+ - physical_network
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the network belongs.
+ - If not set, default zone is used.
+ type: str
+ broadcast_domain_range:
+ description:
+ - broadcast domain range for the physical network[Pod or Zone].
+ choices: [ POD, ZONE ]
+ type: str
+ domain:
+ description:
+ - Domain the network is owned by.
+ type: str
+ isolation_method:
+ description:
+ - Isolation method for the physical network.
+ choices: [ VLAN, GRE, L3 ]
+ type: str
+ network_speed:
+ description:
+ - The speed for the physical network.
+ choices: [1G, 10G]
+ type: str
+ tags:
+ description:
+ - A tag to identify this network.
+ - Physical networks support only one tag.
+ - To remove an existing tag pass an empty string.
+ aliases:
+ - tag
+ type: str
+ vlan:
+ description:
+ - The VLAN/VNI Ranges of the physical network.
+ type: str
+ nsps_enabled:
+ description:
+ - List of Network Service Providers to enable.
+ type: list
+ elements: str
+ nsps_disabled:
+ description:
+ - List of Network Service Providers to disable.
+ type: list
+ elements: str
+ state:
+ description:
+ - State of the physical network.
+ default: present
+ type: str
+ choices: [ present, absent, disabled, enabled ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Ensure a network is present
+ ngine_io.cloudstack.cs_physical_network:
+ name: net01
+ zone: zone01
+ isolation_method: VLAN
+ broadcast_domain_range: ZONE
+
+- name: Set a tag on a network
+ ngine_io.cloudstack.cs_physical_network:
+ name: net01
+ tag: overlay
+
+- name: Remove tag on a network
+ ngine_io.cloudstack.cs_physical_network:
+ name: net01
+ tag: ""
+
+- name: Ensure a network is enabled with specific nsps enabled
+ ngine_io.cloudstack.cs_physical_network:
+ name: net01
+ zone: zone01
+ isolation_method: VLAN
+ vlan: 100-200,300-400
+ broadcast_domain_range: ZONE
+ state: enabled
+ nsps_enabled:
+ - virtualrouter
+ - internallbvm
+ - vpcvirtualrouter
+
+- name: Ensure a network is disabled
+ ngine_io.cloudstack.cs_physical_network:
+ name: net01
+ zone: zone01
+ state: disabled
+
+- name: Ensure a network is enabled
+ ngine_io.cloudstack.cs_physical_network:
+ name: net01
+ zone: zone01
+ state: enabled
+
+- name: Ensure a network is absent
+ ngine_io.cloudstack.cs_physical_network:
+ name: net01
+ zone: zone01
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the network.
+ returned: success
+ type: str
+ sample: 3f8f25cd-c498-443f-9058-438cfbcbff50
+name:
+ description: Name of the network.
+ returned: success
+ type: str
+ sample: net01
+state:
+ description: State of the network [Enabled/Disabled].
+ returned: success
+ type: str
+ sample: Enabled
+broadcast_domain_range:
+ description: broadcastdomainrange of the network [POD / ZONE].
+ returned: success
+ type: str
+ sample: ZONE
+isolation_method:
+ description: isolationmethod of the network [VLAN/GRE/L3].
+ returned: success
+ type: str
+ sample: VLAN
+network_speed:
+ description: networkspeed of the network [1G/10G].
+ returned: success
+ type: str
+ sample: 1G
+zone:
+ description: Name of zone the physical network is in.
+ returned: success
+ type: str
+ sample: ch-gva-2
+domain:
+ description: Name of domain the network is in.
+ returned: success
+ type: str
+ sample: domain1
+nsps:
+ description: list of enabled or disabled Network Service Providers
+ type: complex
+ returned: on enabling/disabling of Network Service Providers
+ contains:
+ enabled:
+ description: list of Network Service Providers that were enabled
+ returned: on Network Service Provider enabling
+ type: list
+ sample:
+ - virtualrouter
+ disabled:
+ description: list of Network Service Providers that were disabled
+ returned: on Network Service Provider disabling
+ type: list
+ sample:
+ - internallbvm
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackPhysicalNetwork(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackPhysicalNetwork, self).__init__(module)
+ self.returns = {
+ 'isolationmethods': 'isolation_method',
+ 'broadcastdomainrange': 'broadcast_domain_range',
+ 'networkspeed': 'network_speed',
+ 'vlan': 'vlan',
+ 'tags': 'tags',
+ }
+ self.nsps = []
+ self.vrouters = None
+ self.loadbalancers = None
+
+ def _get_common_args(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'isolationmethods': self.module.params.get('isolation_method'),
+ 'broadcastdomainrange': self.module.params.get('broadcast_domain_range'),
+ 'networkspeed': self.module.params.get('network_speed'),
+ 'tags': self.module.params.get('tags'),
+ 'vlan': self.module.params.get('vlan'),
+ }
+
+ state = self.module.params.get('state')
+ if state in ['enabled', 'disabled']:
+ args['state'] = state.capitalize()
+ return args
+
+ def get_physical_network(self, key=None):
+ physical_network = self.module.params.get('name')
+ if self.physical_network:
+ return self._get_by_key(key, self.physical_network)
+
+ args = {
+ 'zoneid': self.get_zone(key='id')
+ }
+ physical_networks = self.query_api('listPhysicalNetworks', **args)
+ if physical_networks:
+ for net in physical_networks['physicalnetwork']:
+ if physical_network.lower() in [net['name'].lower(), net['id']]:
+ self.physical_network = net
+ self.result['physical_network'] = net['name']
+ break
+
+ return self._get_by_key(key, self.physical_network)
+
+ def get_nsp(self, name=None):
+ if not self.nsps:
+ args = {
+ 'physicalnetworkid': self.get_physical_network(key='id')
+ }
+ res = self.query_api('listNetworkServiceProviders', **args)
+
+ self.nsps = res['networkserviceprovider']
+
+ names = []
+ for nsp in self.nsps:
+ names.append(nsp['name'])
+ if nsp['name'].lower() == name.lower():
+ return nsp
+
+ self.module.fail_json(msg="Failed: '{0}' not in network service providers list '[{1}]'".format(name, names))
+
+ def update_nsp(self, name=None, state=None, service_list=None):
+ nsp = self.get_nsp(name)
+ if not service_list and nsp['state'] == state:
+ return nsp
+
+ args = {
+ 'id': nsp['id'],
+ 'servicelist': service_list,
+ 'state': state
+ }
+ if not self.module.check_mode:
+ res = self.query_api('updateNetworkServiceProvider', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ nsp = self.poll_job(res, 'networkserviceprovider')
+
+ self.result['changed'] = True
+ return nsp
+
+ def get_vrouter_element(self, nsp_name='virtualrouter'):
+ nsp = self.get_nsp(nsp_name)
+ nspid = nsp['id']
+ if self.vrouters is None:
+ self.vrouters = dict()
+ res = self.query_api('listVirtualRouterElements', )
+ for vrouter in res['virtualrouterelement']:
+ self.vrouters[vrouter['nspid']] = vrouter
+
+ if nspid not in self.vrouters:
+ self.module.fail_json(msg="Failed: No VirtualRouterElement found for nsp '%s'" % nsp_name)
+
+ return self.vrouters[nspid]
+
+ def get_loadbalancer_element(self, nsp_name='internallbvm'):
+ nsp = self.get_nsp(nsp_name)
+ nspid = nsp['id']
+ if self.loadbalancers is None:
+ self.loadbalancers = dict()
+ res = self.query_api('listInternalLoadBalancerElements', )
+ for loadbalancer in res['internalloadbalancerelement']:
+ self.loadbalancers[loadbalancer['nspid']] = loadbalancer
+
+ if nspid not in self.loadbalancers:
+ self.module.fail_json(msg="Failed: No Loadbalancer found for nsp '%s'" % nsp_name)
+
+ return self.loadbalancers[nspid]
+
+ def set_vrouter_element_state(self, enabled, nsp_name='virtualrouter'):
+ vrouter = self.get_vrouter_element(nsp_name)
+ if vrouter['enabled'] == enabled:
+ return vrouter
+
+ args = {
+ 'id': vrouter['id'],
+ 'enabled': enabled
+ }
+ if not self.module.check_mode:
+ res = self.query_api('configureVirtualRouterElement', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vrouter = self.poll_job(res, 'virtualrouterelement')
+
+ self.result['changed'] = True
+ return vrouter
+
+ def set_loadbalancer_element_state(self, enabled, nsp_name='internallbvm'):
+ loadbalancer = self.get_loadbalancer_element(nsp_name=nsp_name)
+ if loadbalancer['enabled'] == enabled:
+ return loadbalancer
+
+ args = {
+ 'id': loadbalancer['id'],
+ 'enabled': enabled
+ }
+ if not self.module.check_mode:
+ res = self.query_api('configureInternalLoadBalancerElement', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ loadbalancer = self.poll_job(res, 'internalloadbalancerelement')
+
+ self.result['changed'] = True
+ return loadbalancer
+
+ def present_network(self):
+ network = self.get_physical_network()
+ if network:
+ network = self._update_network()
+ else:
+ network = self._create_network()
+ return network
+
+ def _create_network(self):
+ self.result['changed'] = True
+ args = dict(zoneid=self.get_zone(key='id'))
+ args.update(self._get_common_args())
+ if self.get_domain(key='id'):
+ args['domainid'] = self.get_domain(key='id')
+
+ if not self.module.check_mode:
+ resource = self.query_api('createPhysicalNetwork', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.network = self.poll_job(resource, 'physicalnetwork')
+
+ return self.network
+
+ def _update_network(self):
+ network = self.get_physical_network()
+
+ args = dict(id=network['id'])
+ args.update(self._get_common_args())
+
+ if self.has_changed(args, network):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ resource = self.query_api('updatePhysicalNetwork', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.physical_network = self.poll_job(resource, 'physicalnetwork')
+ return self.physical_network
+
+ def absent_network(self):
+ physical_network = self.get_physical_network()
+ if physical_network:
+ self.result['changed'] = True
+ args = {
+ 'id': physical_network['id'],
+ }
+ if not self.module.check_mode:
+ resource = self.query_api('deletePhysicalNetwork', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(resource, 'success')
+
+ return physical_network
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True, aliases=['physical_network']),
+ zone=dict(),
+ domain=dict(),
+ vlan=dict(),
+ nsps_disabled=dict(type='list', elements='str'),
+ nsps_enabled=dict(type='list', elements='str'),
+ network_speed=dict(choices=['1G', '10G']),
+ broadcast_domain_range=dict(choices=['POD', 'ZONE']),
+ isolation_method=dict(choices=['VLAN', 'GRE', 'L3']),
+ state=dict(choices=['present', 'enabled', 'disabled', 'absent'], default='present'),
+ tags=dict(aliases=['tag']),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_network = AnsibleCloudStackPhysicalNetwork(module)
+ state = module.params.get('state')
+ nsps_disabled = module.params.get('nsps_disabled', [])
+ nsps_enabled = module.params.get('nsps_enabled', [])
+
+ if state in ['absent']:
+ network = acs_network.absent_network()
+ else:
+ network = acs_network.present_network()
+ if nsps_disabled is not None:
+ for name in nsps_disabled:
+ acs_network.update_nsp(name=name, state='Disabled')
+
+ if nsps_enabled is not None:
+ for nsp_name in nsps_enabled:
+ if nsp_name.lower() in ['virtualrouter', 'vpcvirtualrouter']:
+ acs_network.set_vrouter_element_state(enabled=True, nsp_name=nsp_name)
+ elif nsp_name.lower() == 'internallbvm':
+ acs_network.set_loadbalancer_element_state(enabled=True, nsp_name=nsp_name)
+
+ acs_network.update_nsp(name=nsp_name, state='Enabled')
+
+ result = acs_network.get_result(network)
+
+ if nsps_enabled:
+ result['nsps_enabled'] = nsps_enabled
+ if nsps_disabled:
+ result['nsps_disabled'] = nsps_disabled
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_pod.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_pod.py
new file mode 100644
index 00000000..90ab2ef5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_pod.py
@@ -0,0 +1,289 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_pod
+short_description: Manages pods on Apache CloudStack based clouds.
+description:
+ - Create, update, delete pods.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the pod.
+ type: str
+ required: true
+ id:
+ description:
+ - uuid of the existing pod.
+ type: str
+ start_ip:
+ description:
+ - Starting IP address for the Pod.
+ - Required on I(state=present)
+ type: str
+ end_ip:
+ description:
+ - Ending IP address for the Pod.
+ type: str
+ netmask:
+ description:
+ - Netmask for the Pod.
+ - Required on I(state=present)
+ type: str
+ gateway:
+ description:
+ - Gateway for the Pod.
+ - Required on I(state=present)
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the pod belongs to.
+ - If not set, default zone is used.
+ type: str
+ state:
+ description:
+ - State of the pod.
+ type: str
+ default: present
+ choices: [ present, enabled, disabled, absent ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Ensure a pod is present
+ ngine_io.cloudstack.cs_pod:
+ name: pod1
+ zone: ch-zrh-ix-01
+ start_ip: 10.100.10.101
+ gateway: 10.100.10.1
+ netmask: 255.255.255.0
+
+- name: Ensure a pod is disabled
+ ngine_io.cloudstack.cs_pod:
+ name: pod1
+ zone: ch-zrh-ix-01
+ state: disabled
+
+- name: Ensure a pod is enabled
+ ngine_io.cloudstack.cs_pod:
+ name: pod1
+ zone: ch-zrh-ix-01
+ state: enabled
+
+- name: Ensure a pod is absent
+ ngine_io.cloudstack.cs_pod:
+ name: pod1
+ zone: ch-zrh-ix-01
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the pod.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: Name of the pod.
+ returned: success
+ type: str
+ sample: pod01
+start_ip:
+ description: Starting IP of the pod.
+ returned: success
+ type: str
+ sample: 10.100.1.101
+end_ip:
+ description: Ending IP of the pod.
+ returned: success
+ type: str
+ sample: 10.100.1.254
+netmask:
+ description: Netmask of the pod.
+ returned: success
+ type: str
+ sample: 255.255.255.0
+gateway:
+ description: Gateway of the pod.
+ returned: success
+ type: str
+ sample: 10.100.1.1
+allocation_state:
+ description: State of the pod.
+ returned: success
+ type: str
+ sample: Enabled
+zone:
+ description: Name of zone the pod is in.
+ returned: success
+ type: str
+ sample: ch-gva-2
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackPod(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackPod, self).__init__(module)
+ self.returns = {
+ 'endip': 'end_ip',
+ 'startip': 'start_ip',
+ 'gateway': 'gateway',
+ 'netmask': 'netmask',
+ 'allocationstate': 'allocation_state',
+ }
+ self.pod = None
+
+ def _get_common_pod_args(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'zoneid': self.get_zone(key='id'),
+ 'startip': self.module.params.get('start_ip'),
+ 'endip': self.module.params.get('end_ip'),
+ 'netmask': self.module.params.get('netmask'),
+ 'gateway': self.module.params.get('gateway')
+ }
+ state = self.module.params.get('state')
+ if state in ['enabled', 'disabled']:
+ args['allocationstate'] = state.capitalize()
+ return args
+
+ def get_pod(self):
+ if not self.pod:
+ args = {
+ 'zoneid': self.get_zone(key='id')
+ }
+
+ uuid = self.module.params.get('id')
+ if uuid:
+ args['id'] = uuid
+ else:
+ args['name'] = self.module.params.get('name')
+
+ pods = self.query_api('listPods', **args)
+ if pods:
+ for pod in pods['pod']:
+ if not args['name']:
+ self.pod = self._transform_ip_list(pod)
+ break
+ elif args['name'] == pod['name']:
+ self.pod = self._transform_ip_list(pod)
+ break
+ return self.pod
+
+ def present_pod(self):
+ pod = self.get_pod()
+ if pod:
+ pod = self._update_pod()
+ else:
+ pod = self._create_pod()
+ return pod
+
+ def _create_pod(self):
+ required_params = [
+ 'start_ip',
+ 'netmask',
+ 'gateway',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ pod = None
+ self.result['changed'] = True
+ args = self._get_common_pod_args()
+ if not self.module.check_mode:
+ res = self.query_api('createPod', **args)
+ pod = res['pod']
+ return pod
+
+ def _update_pod(self):
+ pod = self.get_pod()
+ args = self._get_common_pod_args()
+ args['id'] = pod['id']
+
+ if self.has_changed(args, pod):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('updatePod', **args)
+ pod = res['pod']
+ return pod
+
+ def absent_pod(self):
+ pod = self.get_pod()
+ if pod:
+ self.result['changed'] = True
+
+ args = {
+ 'id': pod['id']
+ }
+ if not self.module.check_mode:
+ self.query_api('deletePod', **args)
+ return pod
+
+ def _transform_ip_list(self, resource):
+ """ Workaround for 4.11 return API break """
+ keys = ['endip', 'startip']
+ if resource:
+ for key in keys:
+ if key in resource and isinstance(resource[key], list):
+ resource[key] = resource[key][0]
+ return resource
+
+ def get_result(self, pod):
+ pod = self._transform_ip_list(pod)
+ super(AnsibleCloudStackPod, self).get_result(pod)
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ id=dict(),
+ name=dict(required=True),
+ gateway=dict(),
+ netmask=dict(),
+ start_ip=dict(),
+ end_ip=dict(),
+ zone=dict(),
+ state=dict(choices=['present', 'enabled', 'disabled', 'absent'], default='present'),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_pod = AnsibleCloudStackPod(module)
+ state = module.params.get('state')
+ if state in ['absent']:
+ pod = acs_pod.absent_pod()
+ else:
+ pod = acs_pod.present_pod()
+
+ result = acs_pod.get_result(pod)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_portforward.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_portforward.py
new file mode 100644
index 00000000..3c80ccbb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_portforward.py
@@ -0,0 +1,398 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_portforward
+short_description: Manages port forwarding rules on Apache CloudStack based clouds.
+description:
+ - Create, update and remove port forwarding rules.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ ip_address:
+ description:
+ - Public IP address the rule is assigned to.
+ type: str
+ required: true
+ vm:
+ description:
+ - Name of virtual machine which we make the port forwarding rule for.
+ - Required if I(state=present).
+ type: str
+ state:
+ description:
+ - State of the port forwarding rule.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ protocol:
+ description:
+ - Protocol of the port forwarding rule.
+ type: str
+ default: tcp
+ choices: [ tcp, udp ]
+ public_port:
+ description:
+ - Start public port for this rule.
+ type: int
+ required: true
+ public_end_port:
+ description:
+ - End public port for this rule.
+ - If not specified equal I(public_port).
+ type: int
+ private_port:
+ description:
+ - Start private port for this rule.
+ type: int
+ required: true
+ private_end_port:
+ description:
+ - End private port for this rule.
+ - If not specified equal I(private_port).
+ type: int
+ open_firewall:
+ description:
+ - Whether the firewall rule for public port should be created, while creating the new rule.
+ - Not supported when forwarding ports in a VPC.
+ - Use M(cs_firewall) for managing firewall rules.
+ default: no
+ type: bool
+ vm_guest_ip:
+ description:
+ - VM guest NIC secondary IP address for the port forwarding rule.
+ type: str
+ network:
+ description:
+ - Name of the network. Required when forwarding ports in a VPC.
+ type: str
+ vpc:
+ description:
+ - Name of the VPC.
+ type: str
+ domain:
+ description:
+ - Domain the I(vm) is related to.
+ type: str
+ account:
+ description:
+ - Account the I(vm) is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the I(vm) is located in.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the virtual machine is in.
+ - If not set, default zone is used.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "To delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: 1.2.3.4:80 -> web01:8080
+ ngine_io.cloudstack.cs_portforward:
+ ip_address: 1.2.3.4
+ vm: web01
+ public_port: 80
+ private_port: 8080
+
+- name: forward SSH and open firewall
+ ngine_io.cloudstack.cs_portforward:
+ ip_address: '{{ public_ip }}'
+ vm: '{{ inventory_hostname }}'
+ public_port: '{{ ansible_ssh_port }}'
+ private_port: 22
+ open_firewall: true
+
+- name: forward DNS traffic, but do not open firewall
+ ngine_io.cloudstack.cs_portforward:
+ ip_address: 1.2.3.4
+ vm: '{{ inventory_hostname }}'
+ public_port: 53
+ private_port: 53
+ protocol: udp
+
+- name: remove ssh port forwarding
+ ngine_io.cloudstack.cs_portforward:
+ ip_address: 1.2.3.4
+ public_port: 22
+ private_port: 22
+ state: absent
+
+- name: forward SSH in backend tier of VPC
+ ngine_io.cloudstack.cs_portforward:
+ ip_address: '{{ public_ip }}'
+ vm: '{{ inventory_hostname }}'
+ public_port: '{{ ansible_ssh_port }}'
+ private_port: 22
+ vpc: myVPC
+ network: backend
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the public IP address.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+ip_address:
+ description: Public IP address.
+ returned: success
+ type: str
+ sample: 1.2.3.4
+protocol:
+ description: Protocol.
+ returned: success
+ type: str
+ sample: tcp
+private_port:
+ description: Start port on the virtual machine's IP address.
+ returned: success
+ type: int
+ sample: 80
+private_end_port:
+ description: End port on the virtual machine's IP address.
+ returned: success
+ type: int
+ sample: 80
+public_port:
+ description: Start port on the public IP address.
+ returned: success
+ type: int
+ sample: 80
+public_end_port:
+ description: End port on the public IP address.
+ returned: success
+ type: int
+ sample: 80
+tags:
+ description: Tags related to the port forwarding.
+ returned: success
+ type: list
+ sample: []
+vm_name:
+ description: Name of the virtual machine.
+ returned: success
+ type: str
+ sample: web-01
+vm_display_name:
+ description: Display name of the virtual machine.
+ returned: success
+ type: str
+ sample: web-01
+vm_guest_ip:
+ description: IP of the virtual machine.
+ returned: success
+ type: str
+ sample: 10.101.65.152
+vpc:
+ description: Name of the VPC.
+ returned: success
+ type: str
+ sample: my_vpc
+network:
+ description: Name of the network.
+ returned: success
+ type: str
+ sample: dmz
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together
+
+
+class AnsibleCloudStackPortforwarding(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackPortforwarding, self).__init__(module)
+ self.returns = {
+ 'virtualmachinedisplayname': 'vm_display_name',
+ 'virtualmachinename': 'vm_name',
+ 'ipaddress': 'ip_address',
+ 'vmguestip': 'vm_guest_ip',
+ 'publicip': 'public_ip',
+ 'protocol': 'protocol',
+ }
+ # these values will be casted to int
+ self.returns_to_int = {
+ 'publicport': 'public_port',
+ 'publicendport': 'public_end_port',
+ 'privateport': 'private_port',
+ 'privateendport': 'private_end_port',
+ }
+ self.portforwarding_rule = None
+
+ def get_portforwarding_rule(self):
+ if not self.portforwarding_rule:
+ protocol = self.module.params.get('protocol')
+ public_port = self.module.params.get('public_port')
+
+ args = {
+ 'ipaddressid': self.get_ip_address(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ }
+ portforwarding_rules = self.query_api('listPortForwardingRules', **args)
+
+ if portforwarding_rules and 'portforwardingrule' in portforwarding_rules:
+ for rule in portforwarding_rules['portforwardingrule']:
+ if (protocol == rule['protocol'] and
+ public_port == int(rule['publicport'])):
+ self.portforwarding_rule = rule
+ break
+ return self.portforwarding_rule
+
+ def present_portforwarding_rule(self):
+ portforwarding_rule = self.get_portforwarding_rule()
+ if portforwarding_rule:
+ portforwarding_rule = self.update_portforwarding_rule(portforwarding_rule)
+ else:
+ portforwarding_rule = self.create_portforwarding_rule()
+
+ if portforwarding_rule:
+ portforwarding_rule = self.ensure_tags(resource=portforwarding_rule, resource_type='PortForwardingRule')
+ self.portforwarding_rule = portforwarding_rule
+
+ return portforwarding_rule
+
+ def create_portforwarding_rule(self):
+ args = {
+ 'protocol': self.module.params.get('protocol'),
+ 'publicport': self.module.params.get('public_port'),
+ 'publicendport': self.get_or_fallback('public_end_port', 'public_port'),
+ 'privateport': self.module.params.get('private_port'),
+ 'privateendport': self.get_or_fallback('private_end_port', 'private_port'),
+ 'openfirewall': self.module.params.get('open_firewall'),
+ 'vmguestip': self.get_vm_guest_ip(),
+ 'ipaddressid': self.get_ip_address(key='id'),
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'networkid': self.get_network(key='id'),
+ }
+
+ portforwarding_rule = None
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ portforwarding_rule = self.query_api('createPortForwardingRule', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ portforwarding_rule = self.poll_job(portforwarding_rule, 'portforwardingrule')
+ return portforwarding_rule
+
+ def update_portforwarding_rule(self, portforwarding_rule):
+ args = {
+ 'protocol': self.module.params.get('protocol'),
+ 'publicport': self.module.params.get('public_port'),
+ 'publicendport': self.get_or_fallback('public_end_port', 'public_port'),
+ 'privateport': self.module.params.get('private_port'),
+ 'privateendport': self.get_or_fallback('private_end_port', 'private_port'),
+ 'vmguestip': self.get_vm_guest_ip(),
+ 'ipaddressid': self.get_ip_address(key='id'),
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'networkid': self.get_network(key='id'),
+ }
+
+ if self.has_changed(args, portforwarding_rule):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ # API broken in 4.2.1?, workaround using remove/create instead of update
+ # portforwarding_rule = self.query_api('updatePortForwardingRule', **args)
+ self.absent_portforwarding_rule()
+ portforwarding_rule = self.query_api('createPortForwardingRule', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ portforwarding_rule = self.poll_job(portforwarding_rule, 'portforwardingrule')
+ return portforwarding_rule
+
+ def absent_portforwarding_rule(self):
+ portforwarding_rule = self.get_portforwarding_rule()
+
+ if portforwarding_rule:
+ self.result['changed'] = True
+ args = {
+ 'id': portforwarding_rule['id'],
+ }
+ if not self.module.check_mode:
+ res = self.query_api('deletePortForwardingRule', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'portforwardingrule')
+ return portforwarding_rule
+
+ def get_result(self, portforwarding_rule):
+ super(AnsibleCloudStackPortforwarding, self).get_result(portforwarding_rule)
+ if portforwarding_rule:
+ for search_key, return_key in self.returns_to_int.items():
+ if search_key in portforwarding_rule:
+ self.result[return_key] = int(portforwarding_rule[search_key])
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ ip_address=dict(required=True),
+ protocol=dict(choices=['tcp', 'udp'], default='tcp'),
+ public_port=dict(type='int', required=True),
+ public_end_port=dict(type='int'),
+ private_port=dict(type='int', required=True),
+ private_end_port=dict(type='int'),
+ state=dict(choices=['present', 'absent'], default='present'),
+ open_firewall=dict(type='bool', default=False),
+ vm_guest_ip=dict(),
+ vm=dict(),
+ vpc=dict(),
+ network=dict(),
+ zone=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ poll_async=dict(type='bool', default=True),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_pf = AnsibleCloudStackPortforwarding(module)
+ state = module.params.get('state')
+ if state in ['absent']:
+ pf_rule = acs_pf.absent_portforwarding_rule()
+ else:
+ pf_rule = acs_pf.present_portforwarding_rule()
+
+ result = acs_pf.get_result(pf_rule)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_project.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_project.py
new file mode 100644
index 00000000..c52444ed
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_project.py
@@ -0,0 +1,271 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_project
+short_description: Manages projects on Apache CloudStack based clouds.
+description:
+ - Create, update, suspend, activate and remove projects.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the project.
+ type: str
+ required: true
+ display_text:
+ description:
+ - Display text of the project.
+ - If not specified, I(name) will be used as I(display_text).
+ type: str
+ state:
+ description:
+ - State of the project.
+ type: str
+ default: present
+ choices: [ present, absent, active, suspended ]
+ domain:
+ description:
+ - Domain the project is related to.
+ type: str
+ account:
+ description:
+ - Account the project is related to.
+ type: str
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "If you want to delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a project
+ ngine_io.cloudstack.cs_project:
+ name: web
+ tags:
+ - { key: admin, value: john }
+ - { key: foo, value: bar }
+
+- name: Rename a project
+ ngine_io.cloudstack.cs_project:
+ name: web
+ display_text: my web project
+
+- name: Suspend an existing project
+ ngine_io.cloudstack.cs_project:
+ name: web
+ state: suspended
+
+- name: Activate an existing project
+ ngine_io.cloudstack.cs_project:
+ name: web
+ state: active
+
+- name: Remove a project
+ ngine_io.cloudstack.cs_project:
+ name: web
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the project.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: Name of the project.
+ returned: success
+ type: str
+ sample: web project
+display_text:
+ description: Display text of the project.
+ returned: success
+ type: str
+ sample: web project
+state:
+ description: State of the project.
+ returned: success
+ type: str
+ sample: Active
+domain:
+ description: Domain the project is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the project is related to.
+ returned: success
+ type: str
+ sample: example account
+tags:
+ description: List of resource tags associated with the project.
+ returned: success
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackProject(AnsibleCloudStack):
+
+ def get_project(self):
+ if not self.project:
+ project = self.module.params.get('name')
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'fetch_list': True,
+ }
+ projects = self.query_api('listProjects', **args)
+ if projects:
+ for p in projects:
+ if project.lower() in [p['name'].lower(), p['id']]:
+ self.project = p
+ break
+ return self.project
+
+ def present_project(self):
+ project = self.get_project()
+ if not project:
+ project = self.create_project(project)
+ else:
+ project = self.update_project(project)
+ if project:
+ project = self.ensure_tags(resource=project, resource_type='project')
+ # refresh resource
+ self.project = project
+ return project
+
+ def update_project(self, project):
+ args = {
+ 'id': project['id'],
+ 'displaytext': self.get_or_fallback('display_text', 'name')
+ }
+ if self.has_changed(args, project):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ project = self.query_api('updateProject', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if project and poll_async:
+ project = self.poll_job(project, 'project')
+ return project
+
+ def create_project(self, project):
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ 'account': self.get_account('name'),
+ 'domainid': self.get_domain('id')
+ }
+ if not self.module.check_mode:
+ project = self.query_api('createProject', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if project and poll_async:
+ project = self.poll_job(project, 'project')
+ return project
+
+ def state_project(self, state='active'):
+ project = self.present_project()
+
+ if project['state'].lower() != state:
+ self.result['changed'] = True
+
+ args = {
+ 'id': project['id']
+ }
+ if not self.module.check_mode:
+ if state == 'suspended':
+ project = self.query_api('suspendProject', **args)
+ else:
+ project = self.query_api('activateProject', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if project and poll_async:
+ project = self.poll_job(project, 'project')
+ return project
+
+ def absent_project(self):
+ project = self.get_project()
+ if project:
+ self.result['changed'] = True
+
+ args = {
+ 'id': project['id']
+ }
+ if not self.module.check_mode:
+ res = self.query_api('deleteProject', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ res = self.poll_job(res, 'project')
+ return project
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ display_text=dict(),
+ state=dict(choices=['present', 'absent', 'active', 'suspended'], default='present'),
+ domain=dict(),
+ account=dict(),
+ poll_async=dict(type='bool', default=True),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_project = AnsibleCloudStackProject(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ project = acs_project.absent_project()
+
+ elif state in ['active', 'suspended']:
+ project = acs_project.state_project(state=state)
+
+ else:
+ project = acs_project.present_project()
+
+ result = acs_project.get_result(project)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_region.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_region.py
new file mode 100644
index 00000000..327f7c1e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_region.py
@@ -0,0 +1,187 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_region
+short_description: Manages regions on Apache CloudStack based clouds.
+description:
+ - Add, update and remove regions.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ id:
+ description:
+ - ID of the region.
+ - Must be an number (int).
+ type: int
+ required: true
+ name:
+ description:
+ - Name of the region.
+ - Required if I(state=present)
+ type: str
+ endpoint:
+ description:
+ - Endpoint URL of the region.
+ - Required if I(state=present)
+ type: str
+ state:
+ description:
+ - State of the region.
+ type: str
+ default: present
+ choices: [ present, absent ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: create a region
+ ngine_io.cloudstack.cs_region:
+ id: 2
+ name: geneva
+ endpoint: https://cloud.gva.example.com
+
+- name: remove a region with ID 2
+ ngine_io.cloudstack.cs_region:
+ id: 2
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: ID of the region.
+ returned: success
+ type: int
+ sample: 1
+name:
+ description: Name of the region.
+ returned: success
+ type: str
+ sample: local
+endpoint:
+ description: Endpoint of the region.
+ returned: success
+ type: str
+ sample: http://cloud.example.com
+gslb_service_enabled:
+ description: Whether the GSLB service is enabled or not.
+ returned: success
+ type: bool
+ sample: true
+portable_ip_service_enabled:
+ description: Whether the portable IP service is enabled or not.
+ returned: success
+ type: bool
+ sample: true
+'''
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackRegion(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackRegion, self).__init__(module)
+ self.returns = {
+ 'endpoint': 'endpoint',
+ 'gslbserviceenabled': 'gslb_service_enabled',
+ 'portableipserviceenabled': 'portable_ip_service_enabled',
+ }
+
+ def get_region(self):
+ id = self.module.params.get('id')
+ regions = self.query_api('listRegions', id=id)
+ if regions:
+ return regions['region'][0]
+ return None
+
+ def present_region(self):
+ region = self.get_region()
+ if not region:
+ region = self._create_region(region=region)
+ else:
+ region = self._update_region(region=region)
+ return region
+
+ def _create_region(self, region):
+ self.result['changed'] = True
+ args = {
+ 'id': self.module.params.get('id'),
+ 'name': self.module.params.get('name'),
+ 'endpoint': self.module.params.get('endpoint')
+ }
+ if not self.module.check_mode:
+ res = self.query_api('addRegion', **args)
+ region = res['region']
+ return region
+
+ def _update_region(self, region):
+ args = {
+ 'id': self.module.params.get('id'),
+ 'name': self.module.params.get('name'),
+ 'endpoint': self.module.params.get('endpoint')
+ }
+ if self.has_changed(args, region):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateRegion', **args)
+ region = res['region']
+ return region
+
+ def absent_region(self):
+ region = self.get_region()
+ if region:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ self.query_api('removeRegion', id=region['id'])
+ return region
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ id=dict(required=True, type='int'),
+ name=dict(),
+ endpoint=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ required_if=[
+ ('state', 'present', ['name', 'endpoint']),
+ ],
+ supports_check_mode=True
+ )
+
+ acs_region = AnsibleCloudStackRegion(module)
+
+ state = module.params.get('state')
+ if state == 'absent':
+ region = acs_region.absent_region()
+ else:
+ region = acs_region.present_region()
+
+ result = acs_region.get_result(region)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_resourcelimit.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_resourcelimit.py
new file mode 100644
index 00000000..fdca3bdd
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_resourcelimit.py
@@ -0,0 +1,202 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_resourcelimit
+short_description: Manages resource limits on Apache CloudStack based clouds.
+description:
+ - Manage limits of resources for domains, accounts and projects.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ resource_type:
+ description:
+ - Type of the resource.
+ type: str
+ required: true
+ choices:
+ - instance
+ - ip_address
+ - volume
+ - snapshot
+ - template
+ - network
+ - vpc
+ - cpu
+ - memory
+ - primary_storage
+ - secondary_storage
+ aliases: [ type ]
+ limit:
+ description:
+ - Maximum number of the resource.
+ - Default is unlimited C(-1).
+ type: int
+ default: -1
+ aliases: [ max ]
+ domain:
+ description:
+ - Domain the resource is related to.
+ type: str
+ account:
+ description:
+ - Account the resource is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the resource is related to.
+ type: str
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Update a resource limit for instances of a domain
+ ngine_io.cloudstack.cs_resourcelimit:
+ type: instance
+ limit: 10
+ domain: customers
+
+- name: Update a resource limit for instances of an account
+ ngine_io.cloudstack.cs_resourcelimit:
+ type: instance
+ limit: 12
+ account: moserre
+ domain: customers
+'''
+
+RETURN = '''
+---
+recource_type:
+ description: Type of the resource
+ returned: success
+ type: str
+ sample: instance
+limit:
+ description: Maximum number of the resource.
+ returned: success
+ type: int
+ sample: -1
+domain:
+ description: Domain the resource is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the resource is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Project the resource is related to.
+ returned: success
+ type: str
+ sample: example project
+'''
+
+# import cloudstack common
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_required_together,
+ cs_argument_spec
+)
+
+
+RESOURCE_TYPES = {
+ 'instance': 0,
+ 'ip_address': 1,
+ 'volume': 2,
+ 'snapshot': 3,
+ 'template': 4,
+ 'network': 6,
+ 'vpc': 7,
+ 'cpu': 8,
+ 'memory': 9,
+ 'primary_storage': 10,
+ 'secondary_storage': 11,
+}
+
+
+class AnsibleCloudStackResourceLimit(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackResourceLimit, self).__init__(module)
+ self.returns = {
+ 'max': 'limit',
+ }
+
+ def get_resource_type(self):
+ resource_type = self.module.params.get('resource_type')
+ return RESOURCE_TYPES.get(resource_type)
+
+ def get_resource_limit(self):
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'resourcetype': self.get_resource_type()
+ }
+ resource_limit = self.query_api('listResourceLimits', **args)
+ if resource_limit:
+ if 'limit' in resource_limit['resourcelimit'][0]:
+ resource_limit['resourcelimit'][0]['limit'] = int(resource_limit['resourcelimit'][0])
+ return resource_limit['resourcelimit'][0]
+ self.module.fail_json(msg="Resource limit type '%s' not found." % self.module.params.get('resource_type'))
+
+ def update_resource_limit(self):
+ resource_limit = self.get_resource_limit()
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'resourcetype': self.get_resource_type(),
+ 'max': self.module.params.get('limit', -1)
+ }
+
+ if self.has_changed(args, resource_limit):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateResourceLimit', **args)
+ resource_limit = res['resourcelimit']
+ return resource_limit
+
+ def get_result(self, resource_limit):
+ self.result = super(AnsibleCloudStackResourceLimit, self).get_result(resource_limit)
+ self.result['resource_type'] = self.module.params.get('resource_type')
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ resource_type=dict(required=True, choices=list(RESOURCE_TYPES.keys()), aliases=['type']),
+ limit=dict(default=-1, aliases=['max'], type='int'),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_resource_limit = AnsibleCloudStackResourceLimit(module)
+ resource_limit = acs_resource_limit.update_resource_limit()
+ result = acs_resource_limit.get_result(resource_limit)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role.py
new file mode 100644
index 00000000..01f23479
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role.py
@@ -0,0 +1,205 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_role
+short_description: Manages user roles on Apache CloudStack based clouds.
+description:
+ - Create, update, delete user roles.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the role.
+ type: str
+ required: true
+ uuid:
+ description:
+ - ID of the role.
+ - If provided, I(uuid) is used as key.
+ type: str
+ aliases: [ id ]
+ role_type:
+ description:
+ - Type of the role.
+ - Only considered for creation.
+ type: str
+ default: User
+ choices: [ User, DomainAdmin, ResourceAdmin, Admin ]
+ description:
+ description:
+ - Description of the role.
+ type: str
+ state:
+ description:
+ - State of the role.
+ type: str
+ default: present
+ choices: [ present, absent ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Ensure an user role is present
+ ngine_io.cloudstack.cs_role:
+ name: myrole_user
+
+- name: Ensure a role having particular ID is named as myrole_user
+ ngine_io.cloudstack.cs_role:
+ name: myrole_user
+ id: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+
+- name: Ensure a role is absent
+ ngine_io.cloudstack.cs_role:
+ name: myrole_user
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the role.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: Name of the role.
+ returned: success
+ type: str
+ sample: myrole
+description:
+ description: Description of the role.
+ returned: success
+ type: str
+ sample: "This is my role description"
+role_type:
+ description: Type of the role.
+ returned: success
+ type: str
+ sample: User
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackRole(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackRole, self).__init__(module)
+ self.returns = {
+ 'type': 'role_type',
+ }
+
+ def get_role(self):
+ uuid = self.module.params.get('uuid')
+ if uuid:
+ args = {
+ 'id': uuid,
+ }
+ roles = self.query_api('listRoles', **args)
+ if roles:
+ return roles['role'][0]
+ else:
+ args = {
+ 'name': self.module.params.get('name'),
+ }
+ roles = self.query_api('listRoles', **args)
+ if roles:
+ return roles['role'][0]
+ return None
+
+ def present_role(self):
+ role = self.get_role()
+ if role:
+ role = self._update_role(role)
+ else:
+ role = self._create_role(role)
+ return role
+
+ def _create_role(self, role):
+ self.result['changed'] = True
+ args = {
+ 'name': self.module.params.get('name'),
+ 'type': self.module.params.get('role_type'),
+ 'description': self.module.params.get('description'),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createRole', **args)
+ role = res['role']
+ return role
+
+ def _update_role(self, role):
+ args = {
+ 'id': role['id'],
+ 'name': self.module.params.get('name'),
+ 'description': self.module.params.get('description'),
+ }
+ if self.has_changed(args, role):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateRole', **args)
+
+ # The API as in 4.9 does not return an updated role yet
+ if 'role' not in res:
+ role = self.get_role()
+ else:
+ role = res['role']
+ return role
+
+ def absent_role(self):
+ role = self.get_role()
+ if role:
+ self.result['changed'] = True
+ args = {
+ 'id': role['id'],
+ }
+ if not self.module.check_mode:
+ self.query_api('deleteRole', **args)
+ return role
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ uuid=dict(aliases=['id']),
+ name=dict(required=True),
+ description=dict(),
+ role_type=dict(choices=['User', 'DomainAdmin', 'ResourceAdmin', 'Admin'], default='User'),
+ state=dict(choices=['present', 'absent'], default='present'),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_role = AnsibleCloudStackRole(module)
+ state = module.params.get('state')
+ if state == 'absent':
+ role = acs_role.absent_role()
+ else:
+ role = acs_role.present_role()
+
+ result = acs_role.get_result(role)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role_permission.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role_permission.py
new file mode 100644
index 00000000..8755f158
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role_permission.py
@@ -0,0 +1,345 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, David Passante (@dpassante)
+# 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: cs_role_permission
+short_description: Manages role permissions on Apache CloudStack based clouds.
+description:
+ - Create, update and remove CloudStack role permissions.
+ - Managing role permissions only supported in CloudStack >= 4.9.
+author: David Passante (@dpassante)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - The API name of the permission.
+ type: str
+ required: true
+ role:
+ description:
+ - Name or ID of the role.
+ type: str
+ required: true
+ permission:
+ description:
+ - The rule permission, allow or deny. Defaulted to deny.
+ type: str
+ choices: [ allow, deny ]
+ default: deny
+ state:
+ description:
+ - State of the role permission.
+ type: str
+ choices: [ present, absent ]
+ default: present
+ description:
+ description:
+ - The description of the role permission.
+ type: str
+ parent:
+ description:
+ - The parent role permission uuid. use 0 to move this rule at the top of the list.
+ type: str
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a role permission
+ ngine_io.cloudstack.cs_role_permission:
+ role: My_Custom_role
+ name: createVPC
+ permission: allow
+ description: My comments
+
+- name: Remove a role permission
+ ngine_io.cloudstack.cs_role_permission:
+ state: absent
+ role: My_Custom_role
+ name: createVPC
+
+- name: Update a system role permission
+ ngine_io.cloudstack.cs_role_permission:
+ role: Domain Admin
+ name: createVPC
+ permission: deny
+
+- name: Update rules order. Move the rule at the top of list
+ ngine_io.cloudstack.cs_role_permission:
+ role: Domain Admin
+ name: createVPC
+ parent: 0
+'''
+
+RETURN = '''
+---
+id:
+ description: The ID of the role permission.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+name:
+ description: The API name of the permission.
+ returned: success
+ type: str
+ sample: createVPC
+permission:
+ description: The permission type of the api name.
+ returned: success
+ type: str
+ sample: allow
+role_id:
+ description: The ID of the role to which the role permission belongs.
+ returned: success
+ type: str
+ sample: c6f7a5fc-43f8-11e5-a151-feff819cdc7f
+description:
+ description: The description of the role permission
+ returned: success
+ type: str
+ sample: Deny createVPC for users
+'''
+
+from distutils.version import LooseVersion
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackRolePermission(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackRolePermission, self).__init__(module)
+ cloudstack_min_version = LooseVersion('4.9.2')
+
+ self.returns = {
+ 'id': 'id',
+ 'roleid': 'role_id',
+ 'rule': 'name',
+ 'permission': 'permission',
+ 'description': 'description',
+ }
+ self.role_permission = None
+
+ self.cloudstack_version = self._cloudstack_ver()
+
+ if self.cloudstack_version < cloudstack_min_version:
+ self.fail_json(msg="This module requires CloudStack >= %s." % cloudstack_min_version)
+
+ def _cloudstack_ver(self):
+ capabilities = self.get_capabilities()
+ return LooseVersion(capabilities['cloudstackversion'])
+
+ def _get_role_id(self):
+ role = self.module.params.get('role')
+ if not role:
+ return None
+
+ res = self.query_api('listRoles')
+ roles = res['role']
+ if roles:
+ for r in roles:
+ if role in [r['name'], r['id']]:
+ return r['id']
+ self.fail_json(msg="Role '%s' not found" % role)
+
+ def _get_role_perm(self):
+ role_permission = self.role_permission
+
+ args = {
+ 'roleid': self._get_role_id(),
+ }
+
+ rp = self.query_api('listRolePermissions', **args)
+
+ if rp:
+ role_permission = rp['rolepermission']
+
+ return role_permission
+
+ def _get_rule(self, rule=None):
+ if not rule:
+ rule = self.module.params.get('name')
+
+ if self._get_role_perm():
+ for _rule in self._get_role_perm():
+ if rule == _rule['rule'] or rule == _rule['id']:
+ return _rule
+
+ return None
+
+ def _get_rule_order(self):
+ perms = self._get_role_perm()
+ rules = []
+
+ if perms:
+ for i, rule in enumerate(perms):
+ rules.append(rule['id'])
+
+ return rules
+
+ def replace_rule(self):
+ old_rule = self._get_rule()
+
+ if old_rule:
+ rules_order = self._get_rule_order()
+ old_pos = rules_order.index(old_rule['id'])
+
+ self.remove_role_perm()
+
+ new_rule = self.create_role_perm()
+
+ if new_rule:
+ perm_order = self.order_permissions(int(old_pos - 1), new_rule['id'])
+
+ return perm_order
+
+ return None
+
+ def order_permissions(self, parent, rule_id):
+ rules = self._get_rule_order()
+
+ if isinstance(parent, int):
+ parent_pos = parent
+ elif parent == '0':
+ parent_pos = -1
+ else:
+ parent_rule = self._get_rule(parent)
+ if not parent_rule:
+ self.fail_json(msg="Parent rule '%s' not found" % parent)
+
+ parent_pos = rules.index(parent_rule['id'])
+
+ r_id = rules.pop(rules.index(rule_id))
+
+ rules.insert((parent_pos + 1), r_id)
+ rules = ','.join(map(str, rules))
+
+ return rules
+
+ def create_or_update_role_perm(self):
+ role_permission = self._get_rule()
+
+ if not role_permission:
+ role_permission = self.create_role_perm()
+ else:
+ role_permission = self.update_role_perm(role_permission)
+
+ return role_permission
+
+ def create_role_perm(self):
+ role_permission = None
+
+ self.result['changed'] = True
+
+ args = {
+ 'rule': self.module.params.get('name'),
+ 'description': self.module.params.get('description'),
+ 'roleid': self._get_role_id(),
+ 'permission': self.module.params.get('permission'),
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('createRolePermission', **args)
+ role_permission = res['rolepermission']
+
+ return role_permission
+
+ def update_role_perm(self, role_perm):
+ perm_order = None
+
+ if not self.module.params.get('parent'):
+ args = {
+ 'ruleid': role_perm['id'],
+ 'roleid': role_perm['roleid'],
+ 'permission': self.module.params.get('permission'),
+ }
+
+ if self.has_changed(args, role_perm, only_keys=['permission']):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ if self.cloudstack_version >= LooseVersion('4.11.0'):
+ self.query_api('updateRolePermission', **args)
+ role_perm = self._get_rule()
+ else:
+ perm_order = self.replace_rule()
+ else:
+ perm_order = self.order_permissions(self.module.params.get('parent'), role_perm['id'])
+
+ if perm_order:
+ args = {
+ 'roleid': role_perm['roleid'],
+ 'ruleorder': perm_order,
+ }
+
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ self.query_api('updateRolePermission', **args)
+ role_perm = self._get_rule()
+
+ return role_perm
+
+ def remove_role_perm(self):
+ role_permission = self._get_rule()
+
+ if role_permission:
+ self.result['changed'] = True
+
+ args = {
+ 'id': role_permission['id'],
+ }
+
+ if not self.module.check_mode:
+ self.query_api('deleteRolePermission', **args)
+
+ return role_permission
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ role=dict(required=True),
+ name=dict(required=True),
+ permission=dict(choices=['allow', 'deny'], default='deny'),
+ description=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ parent=dict(),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ mutually_exclusive=(
+ ['permission', 'parent'],
+ ),
+ supports_check_mode=True
+ )
+
+ acs_role_perm = AnsibleCloudStackRolePermission(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ role_permission = acs_role_perm.remove_role_perm()
+ else:
+ role_permission = acs_role_perm.create_or_update_role_perm()
+
+ result = acs_role_perm.get_result(role_permission)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_router.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_router.py
new file mode 100644
index 00000000..e14a7609
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_router.py
@@ -0,0 +1,368 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_router
+short_description: Manages routers on Apache CloudStack based clouds.
+description:
+ - Start, restart, stop and destroy routers.
+ - I(state=present) is not able to create routers, use M(cs_network) instead.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the router.
+ type: str
+ required: true
+ service_offering:
+ description:
+ - Name or id of the service offering of the router.
+ type: str
+ domain:
+ description:
+ - Domain the router is related to.
+ type: str
+ account:
+ description:
+ - Account the router is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the router is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone the router is deployed in.
+ - If not set, all zones are used.
+ type: str
+ state:
+ description:
+ - State of the router.
+ type: str
+ default: present
+ choices: [ present, absent, started, stopped, restarted ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+# Ensure the router has the desired service offering, no matter if
+# the router is running or not.
+- name: Present router
+ ngine_io.cloudstack.cs_router:
+ name: r-40-VM
+ service_offering: System Offering for Software Router
+
+- name: Ensure started
+ ngine_io.cloudstack.cs_router:
+ name: r-40-VM
+ state: started
+
+# Ensure started with desired service offering.
+# If the service offerings changes, router will be rebooted.
+- name: Ensure started with desired service offering
+ ngine_io.cloudstack.cs_router:
+ name: r-40-VM
+ service_offering: System Offering for Software Router
+ state: started
+
+- name: Ensure stopped
+ ngine_io.cloudstack.cs_router:
+ name: r-40-VM
+ state: stopped
+
+- name: Remove a router
+ ngine_io.cloudstack.cs_router:
+ name: r-40-VM
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the router.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: Name of the router.
+ returned: success
+ type: str
+ sample: r-40-VM
+created:
+ description: Date of the router was created.
+ returned: success
+ type: str
+ sample: 2014-12-01T14:57:57+0100
+template_version:
+ description: Version of the system VM template.
+ returned: success
+ type: str
+ sample: 4.5.1
+requires_upgrade:
+ description: Whether the router needs to be upgraded to the new template.
+ returned: success
+ type: bool
+ sample: false
+redundant_state:
+ description: Redundant state of the router.
+ returned: success
+ type: str
+ sample: UNKNOWN
+role:
+ description: Role of the router.
+ returned: success
+ type: str
+ sample: VIRTUAL_ROUTER
+zone:
+ description: Name of zone the router is in.
+ returned: success
+ type: str
+ sample: ch-gva-2
+service_offering:
+ description: Name of the service offering the router has.
+ returned: success
+ type: str
+ sample: System Offering For Software Router
+state:
+ description: State of the router.
+ returned: success
+ type: str
+ sample: Active
+domain:
+ description: Domain the router is related to.
+ returned: success
+ type: str
+ sample: ROOT
+account:
+ description: Account the router is related to.
+ returned: success
+ type: str
+ sample: admin
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackRouter(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackRouter, self).__init__(module)
+ self.returns = {
+ 'serviceofferingname': 'service_offering',
+ 'version': 'template_version',
+ 'requiresupgrade': 'requires_upgrade',
+ 'redundantstate': 'redundant_state',
+ 'role': 'role'
+ }
+ self.router = None
+
+ def get_service_offering_id(self):
+ service_offering = self.module.params.get('service_offering')
+ if not service_offering:
+ return None
+
+ args = {
+ 'issystem': True
+ }
+
+ service_offerings = self.query_api('listServiceOfferings', **args)
+ if service_offerings:
+ for s in service_offerings['serviceoffering']:
+ if service_offering in [s['name'], s['id']]:
+ return s['id']
+ self.module.fail_json(msg="Service offering '%s' not found" % service_offering)
+
+ def get_router(self):
+ if not self.router:
+ router = self.module.params.get('name')
+
+ args = {
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'listall': True,
+ 'fetch_list': True,
+ }
+
+ if self.module.params.get('zone'):
+ args['zoneid'] = self.get_zone(key='id')
+
+ routers = self.query_api('listRouters', **args)
+ if routers:
+ for r in routers:
+ if router.lower() in [r['name'].lower(), r['id']]:
+ self.router = r
+ break
+ return self.router
+
+ def start_router(self):
+ router = self.get_router()
+ if not router:
+ self.module.fail_json(msg="Router not found")
+
+ if router['state'].lower() != "running":
+ self.result['changed'] = True
+
+ args = {
+ 'id': router['id'],
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('startRouter', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ router = self.poll_job(res, 'router')
+ return router
+
+ def stop_router(self):
+ router = self.get_router()
+ if not router:
+ self.module.fail_json(msg="Router not found")
+
+ if router['state'].lower() != "stopped":
+ self.result['changed'] = True
+
+ args = {
+ 'id': router['id'],
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('stopRouter', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ router = self.poll_job(res, 'router')
+ return router
+
+ def reboot_router(self):
+ router = self.get_router()
+ if not router:
+ self.module.fail_json(msg="Router not found")
+
+ self.result['changed'] = True
+
+ args = {
+ 'id': router['id'],
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('rebootRouter', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ router = self.poll_job(res, 'router')
+ return router
+
+ def absent_router(self):
+ router = self.get_router()
+ if router:
+ self.result['changed'] = True
+
+ args = {
+ 'id': router['id'],
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('destroyRouter', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'router')
+ return router
+
+ def present_router(self):
+ router = self.get_router()
+ if not router:
+ self.module.fail_json(msg="Router can not be created using the API, see cs_network.")
+
+ args = {
+ 'id': router['id'],
+ 'serviceofferingid': self.get_service_offering_id(),
+ }
+
+ state = self.module.params.get('state')
+
+ if self.has_changed(args, router):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ current_state = router['state'].lower()
+
+ self.stop_router()
+ router = self.query_api('changeServiceForRouter', **args)
+
+ if state in ['restarted', 'started']:
+ router = self.start_router()
+
+ # if state=present we get to the state before the service
+ # offering change.
+ elif state == "present" and current_state == "running":
+ router = self.start_router()
+
+ elif state == "started":
+ router = self.start_router()
+
+ elif state == "stopped":
+ router = self.stop_router()
+
+ elif state == "restarted":
+ router = self.reboot_router()
+
+ return router
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ service_offering=dict(),
+ state=dict(choices=['present', 'started', 'stopped', 'restarted', 'absent'], default="present"),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ zone=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_router = AnsibleCloudStackRouter(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ router = acs_router.absent_router()
+ else:
+ router = acs_router.present_router()
+
+ result = acs_router.get_result(router)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup.py
new file mode 100644
index 00000000..5d8ba2b9
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup.py
@@ -0,0 +1,193 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_securitygroup
+short_description: Manages security groups on Apache CloudStack based clouds.
+description:
+ - Create and remove security groups.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the security group.
+ type: str
+ required: true
+ description:
+ description:
+ - Description of the security group.
+ type: str
+ state:
+ description:
+ - State of the security group.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ domain:
+ description:
+ - Domain the security group is related to.
+ type: str
+ account:
+ description:
+ - Account the security group is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the security group to be created in.
+ type: str
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: create a security group
+ ngine_io.cloudstack.cs_securitygroup:
+ name: default
+ description: default security group
+
+- name: remove a security group
+ ngine_io.cloudstack.cs_securitygroup:
+ name: default
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the security group.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+name:
+ description: Name of security group.
+ returned: success
+ type: str
+ sample: app
+description:
+ description: Description of security group.
+ returned: success
+ type: str
+ sample: application security group
+tags:
+ description: List of resource tags associated with the security group.
+ returned: success
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+project:
+ description: Name of project the security group is related to.
+ returned: success
+ type: str
+ sample: Production
+domain:
+ description: Domain the security group is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the security group is related to.
+ returned: success
+ type: str
+ sample: example account
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together
+
+
+class AnsibleCloudStackSecurityGroup(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackSecurityGroup, self).__init__(module)
+ self.security_group = None
+
+ def get_security_group(self):
+ if not self.security_group:
+
+ args = {
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'securitygroupname': self.module.params.get('name'),
+ }
+ sgs = self.query_api('listSecurityGroups', **args)
+ if sgs:
+ self.security_group = sgs['securitygroup'][0]
+ return self.security_group
+
+ def create_security_group(self):
+ security_group = self.get_security_group()
+ if not security_group:
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'description': self.module.params.get('description'),
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('createSecurityGroup', **args)
+ security_group = res['securitygroup']
+
+ return security_group
+
+ def remove_security_group(self):
+ security_group = self.get_security_group()
+ if security_group:
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ }
+
+ if not self.module.check_mode:
+ self.query_api('deleteSecurityGroup', **args)
+
+ return security_group
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ description=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ project=dict(),
+ account=dict(),
+ domain=dict(),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_sg = AnsibleCloudStackSecurityGroup(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ sg = acs_sg.remove_security_group()
+ else:
+ sg = acs_sg.create_security_group()
+
+ result = acs_sg.get_result(sg)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup_rule.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup_rule.py
new file mode 100644
index 00000000..2bd269e8
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup_rule.py
@@ -0,0 +1,379 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_securitygroup_rule
+short_description: Manages security group rules on Apache CloudStack based clouds.
+description:
+ - Add and remove security group rules.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ security_group:
+ description:
+ - Name of the security group the rule is related to. The security group must be existing.
+ type: str
+ required: true
+ state:
+ description:
+ - State of the security group rule.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ protocol:
+ description:
+ - Protocol of the security group rule.
+ type: str
+ default: tcp
+ choices: [ tcp, udp, icmp, ah, esp, gre ]
+ type:
+ description:
+ - Ingress or egress security group rule.
+ type: str
+ default: ingress
+ choices: [ ingress, egress ]
+ cidr:
+ description:
+ - CIDR (full notation) to be used for security group rule.
+ type: str
+ default: 0.0.0.0/0
+ user_security_group:
+ description:
+ - Security group this rule is based of.
+ type: str
+ start_port:
+ description:
+ - Start port for this rule. Required if I(protocol=tcp) or I(protocol=udp).
+ type: int
+ aliases: [ port ]
+ end_port:
+ description:
+ - End port for this rule. Required if I(protocol=tcp) or I(protocol=udp), but I(start_port) will be used if not set.
+ type: int
+ icmp_type:
+ description:
+ - Type of the icmp message being sent. Required if I(protocol=icmp).
+ type: int
+ icmp_code:
+ description:
+ - Error code for this icmp message. Required if I(protocol=icmp).
+ type: int
+ project:
+ description:
+ - Name of the project the security group to be created in.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+---
+- name: allow inbound port 80/tcp from 1.2.3.4 added to security group 'default'
+ ngine_io.cloudstack.cs_securitygroup_rule:
+ security_group: default
+ port: 80
+ cidr: 1.2.3.4/32
+
+- name: allow tcp/udp outbound added to security group 'default'
+ ngine_io.cloudstack.cs_securitygroup_rule:
+ security_group: default
+ type: egress
+ start_port: 1
+ end_port: 65535
+ protocol: '{{ item }}'
+ with_items:
+ - tcp
+ - udp
+
+- name: allow inbound icmp from 0.0.0.0/0 added to security group 'default'
+ ngine_io.cloudstack.cs_securitygroup_rule:
+ security_group: default
+ protocol: icmp
+ icmp_code: -1
+ icmp_type: -1
+
+- name: remove rule inbound port 80/tcp from 0.0.0.0/0 from security group 'default'
+ ngine_io.cloudstack.cs_securitygroup_rule:
+ security_group: default
+ port: 80
+ state: absent
+
+- name: allow inbound port 80/tcp from security group web added to security group 'default'
+ ngine_io.cloudstack.cs_securitygroup_rule:
+ security_group: default
+ port: 80
+ user_security_group: web
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the of the rule.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+security_group:
+ description: security group of the rule.
+ returned: success
+ type: str
+ sample: default
+type:
+ description: type of the rule.
+ returned: success
+ type: str
+ sample: ingress
+cidr:
+ description: CIDR of the rule.
+ returned: success and cidr is defined
+ type: str
+ sample: 0.0.0.0/0
+user_security_group:
+ description: user security group of the rule.
+ returned: success and user_security_group is defined
+ type: str
+ sample: default
+protocol:
+ description: protocol of the rule.
+ returned: success
+ type: str
+ sample: tcp
+start_port:
+ description: start port of the rule.
+ returned: success
+ type: int
+ sample: 80
+end_port:
+ description: end port of the rule.
+ returned: success
+ type: int
+ sample: 80
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together
+
+
+class AnsibleCloudStackSecurityGroupRule(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackSecurityGroupRule, self).__init__(module)
+ self.returns = {
+ 'icmptype': 'icmp_type',
+ 'icmpcode': 'icmp_code',
+ 'endport': 'end_port',
+ 'startport': 'start_port',
+ 'protocol': 'protocol',
+ 'cidr': 'cidr',
+ 'securitygroupname': 'user_security_group',
+ }
+
+ def _tcp_udp_match(self, rule, protocol, start_port, end_port):
+ return (protocol in ['tcp', 'udp'] and
+ protocol == rule['protocol'] and
+ start_port == int(rule['startport']) and
+ end_port == int(rule['endport']))
+
+ def _icmp_match(self, rule, protocol, icmp_code, icmp_type):
+ return (protocol == 'icmp' and
+ protocol == rule['protocol'] and
+ icmp_code == int(rule['icmpcode']) and
+ icmp_type == int(rule['icmptype']))
+
+ def _ah_esp_gre_match(self, rule, protocol):
+ return (protocol in ['ah', 'esp', 'gre'] and
+ protocol == rule['protocol'])
+
+ def _type_security_group_match(self, rule, security_group_name):
+ return (security_group_name and
+ 'securitygroupname' in rule and
+ security_group_name == rule['securitygroupname'])
+
+ def _type_cidr_match(self, rule, cidr):
+ return ('cidr' in rule and
+ cidr == rule['cidr'])
+
+ def _get_rule(self, rules):
+ user_security_group_name = self.module.params.get('user_security_group')
+ cidr = self.module.params.get('cidr')
+ protocol = self.module.params.get('protocol')
+ start_port = self.module.params.get('start_port')
+ end_port = self.get_or_fallback('end_port', 'start_port')
+ icmp_code = self.module.params.get('icmp_code')
+ icmp_type = self.module.params.get('icmp_type')
+
+ if protocol in ['tcp', 'udp'] and (start_port is None or end_port is None):
+ self.module.fail_json(msg="no start_port or end_port set for protocol '%s'" % protocol)
+
+ if protocol == 'icmp' and (icmp_type is None or icmp_code is None):
+ self.module.fail_json(msg="no icmp_type or icmp_code set for protocol '%s'" % protocol)
+
+ for rule in rules:
+ if user_security_group_name:
+ type_match = self._type_security_group_match(rule, user_security_group_name)
+ else:
+ type_match = self._type_cidr_match(rule, cidr)
+
+ protocol_match = (self._tcp_udp_match(rule, protocol, start_port, end_port) or
+ self._icmp_match(rule, protocol, icmp_code, icmp_type) or
+ self._ah_esp_gre_match(rule, protocol))
+
+ if type_match and protocol_match:
+ return rule
+ return None
+
+ def get_security_group(self, security_group_name=None):
+ if not security_group_name:
+ security_group_name = self.module.params.get('security_group')
+ args = {
+ 'securitygroupname': security_group_name,
+ 'projectid': self.get_project('id'),
+ }
+ sgs = self.query_api('listSecurityGroups', **args)
+ if not sgs or 'securitygroup' not in sgs:
+ self.module.fail_json(msg="security group '%s' not found" % security_group_name)
+ return sgs['securitygroup'][0]
+
+ def add_rule(self):
+ security_group = self.get_security_group()
+
+ args = {}
+ user_security_group_name = self.module.params.get('user_security_group')
+
+ # the user_security_group and cidr are mutually_exclusive, but cidr is defaulted to 0.0.0.0/0.
+ # that is why we ignore if we have a user_security_group.
+ if user_security_group_name:
+ args['usersecuritygrouplist'] = []
+ user_security_group = self.get_security_group(user_security_group_name)
+ args['usersecuritygrouplist'].append({
+ 'group': user_security_group['name'],
+ 'account': user_security_group['account'],
+ })
+ else:
+ args['cidrlist'] = self.module.params.get('cidr')
+
+ args['protocol'] = self.module.params.get('protocol')
+ args['startport'] = self.module.params.get('start_port')
+ args['endport'] = self.get_or_fallback('end_port', 'start_port')
+ args['icmptype'] = self.module.params.get('icmp_type')
+ args['icmpcode'] = self.module.params.get('icmp_code')
+ args['projectid'] = self.get_project('id')
+ args['securitygroupid'] = security_group['id']
+
+ rule = None
+ res = None
+ sg_type = self.module.params.get('type')
+ if sg_type == 'ingress':
+ if 'ingressrule' in security_group:
+ rule = self._get_rule(security_group['ingressrule'])
+ if not rule:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('authorizeSecurityGroupIngress', **args)
+
+ elif sg_type == 'egress':
+ if 'egressrule' in security_group:
+ rule = self._get_rule(security_group['egressrule'])
+ if not rule:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('authorizeSecurityGroupEgress', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ security_group = self.poll_job(res, 'securitygroup')
+ key = sg_type + "rule" # ingressrule / egressrule
+ if key in security_group:
+ rule = security_group[key][0]
+ return rule
+
+ def remove_rule(self):
+ security_group = self.get_security_group()
+ rule = None
+ res = None
+ sg_type = self.module.params.get('type')
+ if sg_type == 'ingress':
+ rule = self._get_rule(security_group['ingressrule'])
+ if rule:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('revokeSecurityGroupIngress', id=rule['ruleid'])
+
+ elif sg_type == 'egress':
+ rule = self._get_rule(security_group['egressrule'])
+ if rule:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('revokeSecurityGroupEgress', id=rule['ruleid'])
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ res = self.poll_job(res, 'securitygroup')
+ return rule
+
+ def get_result(self, security_group_rule):
+ super(AnsibleCloudStackSecurityGroupRule, self).get_result(security_group_rule)
+ self.result['type'] = self.module.params.get('type')
+ self.result['security_group'] = self.module.params.get('security_group')
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ security_group=dict(required=True),
+ type=dict(choices=['ingress', 'egress'], default='ingress'),
+ cidr=dict(default='0.0.0.0/0'),
+ user_security_group=dict(),
+ protocol=dict(choices=['tcp', 'udp', 'icmp', 'ah', 'esp', 'gre'], default='tcp'),
+ icmp_type=dict(type='int'),
+ icmp_code=dict(type='int'),
+ start_port=dict(type='int', aliases=['port']),
+ end_port=dict(type='int'),
+ state=dict(choices=['present', 'absent'], default='present'),
+ project=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+ required_together = cs_required_together()
+ required_together.extend([
+ ['icmp_type', 'icmp_code'],
+ ])
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=required_together,
+ mutually_exclusive=(
+ ['icmp_type', 'start_port'],
+ ['icmp_type', 'end_port'],
+ ['icmp_code', 'start_port'],
+ ['icmp_code', 'end_port'],
+ ),
+ supports_check_mode=True
+ )
+
+ acs_sg_rule = AnsibleCloudStackSecurityGroupRule(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ sg_rule = acs_sg_rule.remove_rule()
+ else:
+ sg_rule = acs_sg_rule.add_rule()
+
+ result = acs_sg_rule.get_result(sg_rule)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_service_offering.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_service_offering.py
new file mode 100644
index 00000000..8d17d521
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_service_offering.py
@@ -0,0 +1,574 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, 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: cs_service_offering
+description:
+ - Create and delete service offerings for guest and system VMs.
+ - Update display_text of existing service offering.
+short_description: Manages service offerings on Apache CloudStack based clouds.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ disk_bytes_read_rate:
+ description:
+ - Bytes read rate of the disk offering.
+ type: int
+ aliases: [ bytes_read_rate ]
+ disk_bytes_write_rate:
+ description:
+ - Bytes write rate of the disk offering.
+ type: int
+ aliases: [ bytes_write_rate ]
+ cpu_number:
+ description:
+ - The number of CPUs of the service offering.
+ type: int
+ cpu_speed:
+ description:
+ - The CPU speed of the service offering in MHz.
+ type: int
+ limit_cpu_usage:
+ description:
+ - Restrict the CPU usage to committed service offering.
+ type: bool
+ deployment_planner:
+ description:
+ - The deployment planner heuristics used to deploy a VM of this offering.
+ - If not set, the value of global config I(vm.deployment.planner) is used.
+ type: str
+ display_text:
+ description:
+ - Display text of the service offering.
+ - If not set, I(name) will be used as I(display_text) while creating.
+ type: str
+ domain:
+ description:
+ - Domain the service offering is related to.
+ - Public for all domains and subdomains if not set.
+ type: str
+ host_tags:
+ description:
+ - The host tags for this service offering.
+ type: list
+ elements: str
+ aliases:
+ - host_tag
+ hypervisor_snapshot_reserve:
+ description:
+ - Hypervisor snapshot reserve space as a percent of a volume.
+ - Only for managed storage using Xen or VMware.
+ type: int
+ is_iops_customized:
+ description:
+ - Whether compute offering iops is custom or not.
+ type: bool
+ aliases: [ disk_iops_customized ]
+ disk_iops_read_rate:
+ description:
+ - IO requests read rate of the disk offering.
+ type: int
+ disk_iops_write_rate:
+ description:
+ - IO requests write rate of the disk offering.
+ type: int
+ disk_iops_max:
+ description:
+ - Max. iops of the compute offering.
+ type: int
+ disk_iops_min:
+ description:
+ - Min. iops of the compute offering.
+ type: int
+ is_system:
+ description:
+ - Whether it is a system VM offering or not.
+ type: bool
+ default: no
+ is_volatile:
+ description:
+ - Whether the virtual machine needs to be volatile or not.
+ - Every reboot of VM the root disk is detached then destroyed and a fresh root disk is created and attached to VM.
+ type: bool
+ memory:
+ description:
+ - The total memory of the service offering in MB.
+ type: int
+ name:
+ description:
+ - Name of the service offering.
+ type: str
+ required: true
+ network_rate:
+ description:
+ - Data transfer rate in Mb/s allowed.
+ - Supported only for non-system offering and system offerings having I(system_vm_type=domainrouter).
+ type: int
+ offer_ha:
+ description:
+ - Whether HA is set for the service offering.
+ type: bool
+ provisioning_type:
+ description:
+ - Provisioning type used to create volumes.
+ type: str
+ choices:
+ - thin
+ - sparse
+ - fat
+ service_offering_details:
+ description:
+ - Details for planner, used to store specific parameters.
+ - A list of dictionaries having keys C(key) and C(value).
+ type: list
+ elements: dict
+ state:
+ description:
+ - State of the service offering.
+ type: str
+ choices:
+ - present
+ - absent
+ default: present
+ storage_type:
+ description:
+ - The storage type of the service offering.
+ type: str
+ choices:
+ - local
+ - shared
+ system_vm_type:
+ description:
+ - The system VM type.
+ - Required if I(is_system=yes).
+ type: str
+ choices:
+ - domainrouter
+ - consoleproxy
+ - secondarystoragevm
+ storage_tags:
+ description:
+ - The storage tags for this service offering.
+ type: list
+ elements: str
+ aliases:
+ - storage_tag
+ is_customized:
+ description:
+ - Whether the offering is customizable or not.
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a non-volatile compute service offering with local storage
+ ngine_io.cloudstack.cs_service_offering:
+ name: Micro
+ display_text: Micro 512mb 1cpu
+ cpu_number: 1
+ cpu_speed: 2198
+ memory: 512
+ host_tags: eco
+ storage_type: local
+
+- name: Create a volatile compute service offering with shared storage
+ ngine_io.cloudstack.cs_service_offering:
+ name: Tiny
+ display_text: Tiny 1gb 1cpu
+ cpu_number: 1
+ cpu_speed: 2198
+ memory: 1024
+ storage_type: shared
+ is_volatile: yes
+ host_tags: eco
+ storage_tags: eco
+
+- name: Create or update a volatile compute service offering with shared storage
+ ngine_io.cloudstack.cs_service_offering:
+ name: Tiny
+ display_text: Tiny 1gb 1cpu
+ cpu_number: 1
+ cpu_speed: 2198
+ memory: 1024
+ storage_type: shared
+ is_volatile: yes
+ host_tags: eco
+ storage_tags: eco
+
+- name: Create or update a custom compute service offering
+ ngine_io.cloudstack.cs_service_offering:
+ name: custom
+ display_text: custom compute offer
+ is_customized: yes
+ storage_type: shared
+ host_tags: eco
+ storage_tags: eco
+
+- name: Remove a compute service offering
+ ngine_io.cloudstack.cs_service_offering:
+ name: Tiny
+ state: absent
+
+- name: Create or update a system offering for the console proxy
+ ngine_io.cloudstack.cs_service_offering:
+ name: System Offering for Console Proxy 2GB
+ display_text: System Offering for Console Proxy 2GB RAM
+ is_system: yes
+ system_vm_type: consoleproxy
+ cpu_number: 1
+ cpu_speed: 2198
+ memory: 2048
+ storage_type: shared
+ storage_tags: perf
+
+- name: Remove a system offering
+ ngine_io.cloudstack.cs_service_offering:
+ name: System Offering for Console Proxy 2GB
+ is_system: yes
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the service offering
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+cpu_number:
+ description: Number of CPUs in the service offering
+ returned: success
+ type: int
+ sample: 4
+cpu_speed:
+ description: Speed of CPUs in MHz in the service offering
+ returned: success
+ type: int
+ sample: 2198
+disk_iops_max:
+ description: Max iops of the disk offering
+ returned: success
+ type: int
+ sample: 1000
+disk_iops_min:
+ description: Min iops of the disk offering
+ returned: success
+ type: int
+ sample: 500
+disk_bytes_read_rate:
+ description: Bytes read rate of the service offering
+ returned: success
+ type: int
+ sample: 1000
+disk_bytes_write_rate:
+ description: Bytes write rate of the service offering
+ returned: success
+ type: int
+ sample: 1000
+disk_iops_read_rate:
+ description: IO requests per second read rate of the service offering
+ returned: success
+ type: int
+ sample: 1000
+disk_iops_write_rate:
+ description: IO requests per second write rate of the service offering
+ returned: success
+ type: int
+ sample: 1000
+created:
+ description: Date the offering was created
+ returned: success
+ type: str
+ sample: 2017-11-19T10:48:59+0000
+display_text:
+ description: Display text of the offering
+ returned: success
+ type: str
+ sample: Micro 512mb 1cpu
+domain:
+ description: Domain the offering is into
+ returned: success
+ type: str
+ sample: ROOT
+host_tags:
+ description: List of host tags
+ returned: success
+ type: list
+ sample: [ 'eco' ]
+storage_tags:
+ description: List of storage tags
+ returned: success
+ type: list
+ sample: [ 'eco' ]
+is_system:
+ description: Whether the offering is for system VMs or not
+ returned: success
+ type: bool
+ sample: false
+is_iops_customized:
+ description: Whether the offering uses custom IOPS or not
+ returned: success
+ type: bool
+ sample: false
+is_volatile:
+ description: Whether the offering is volatile or not
+ returned: success
+ type: bool
+ sample: false
+limit_cpu_usage:
+ description: Whether the CPU usage is restricted to committed service offering
+ returned: success
+ type: bool
+ sample: false
+memory:
+ description: Memory of the system offering
+ returned: success
+ type: int
+ sample: 512
+name:
+ description: Name of the system offering
+ returned: success
+ type: str
+ sample: Micro
+offer_ha:
+ description: Whether HA support is enabled in the offering or not
+ returned: success
+ type: bool
+ sample: false
+provisioning_type:
+ description: Provisioning type used to create volumes
+ returned: success
+ type: str
+ sample: thin
+storage_type:
+ description: Storage type used to create volumes
+ returned: success
+ type: str
+ sample: shared
+system_vm_type:
+ description: System VM type of this offering
+ returned: success
+ type: str
+ sample: consoleproxy
+service_offering_details:
+ description: Additioanl service offering details
+ returned: success
+ type: dict
+ sample: "{'vgpuType': 'GRID K180Q','pciDevice':'Group of NVIDIA Corporation GK107GL [GRID K1] GPUs'}"
+network_rate:
+ description: Data transfer rate in megabits per second allowed
+ returned: success
+ type: int
+ sample: 1000
+is_customized:
+ description: Whether the offering is customizable or not
+ returned: success
+ type: bool
+ sample: false
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackServiceOffering(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackServiceOffering, self).__init__(module)
+ self.returns = {
+ 'cpunumber': 'cpu_number',
+ 'cpuspeed': 'cpu_speed',
+ 'deploymentplanner': 'deployment_planner',
+ 'diskBytesReadRate': 'disk_bytes_read_rate',
+ 'diskBytesWriteRate': 'disk_bytes_write_rate',
+ 'diskIopsReadRate': 'disk_iops_read_rate',
+ 'diskIopsWriteRate': 'disk_iops_write_rate',
+ 'maxiops': 'disk_iops_max',
+ 'miniops': 'disk_iops_min',
+ 'hypervisorsnapshotreserve': 'hypervisor_snapshot_reserve',
+ 'iscustomized': 'is_customized',
+ 'iscustomizediops': 'is_iops_customized',
+ 'issystem': 'is_system',
+ 'isvolatile': 'is_volatile',
+ 'limitcpuuse': 'limit_cpu_usage',
+ 'memory': 'memory',
+ 'networkrate': 'network_rate',
+ 'offerha': 'offer_ha',
+ 'provisioningtype': 'provisioning_type',
+ 'serviceofferingdetails': 'service_offering_details',
+ 'storagetype': 'storage_type',
+ 'systemvmtype': 'system_vm_type',
+ 'tags': 'storage_tags',
+ }
+
+ def get_service_offering(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'domainid': self.get_domain(key='id'),
+ 'issystem': self.module.params.get('is_system'),
+ 'systemvmtype': self.module.params.get('system_vm_type'),
+ }
+ service_offerings = self.query_api('listServiceOfferings', **args)
+ if service_offerings:
+ return service_offerings['serviceoffering'][0]
+
+ def present_service_offering(self):
+ service_offering = self.get_service_offering()
+ if not service_offering:
+ service_offering = self._create_offering(service_offering)
+ else:
+ service_offering = self._update_offering(service_offering)
+
+ return service_offering
+
+ def absent_service_offering(self):
+ service_offering = self.get_service_offering()
+ if service_offering:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ args = {
+ 'id': service_offering['id'],
+ }
+ self.query_api('deleteServiceOffering', **args)
+ return service_offering
+
+ def _create_offering(self, service_offering):
+ self.result['changed'] = True
+
+ system_vm_type = self.module.params.get('system_vm_type')
+ is_system = self.module.params.get('is_system')
+
+ required_params = []
+ if is_system and not system_vm_type:
+ required_params.append('system_vm_type')
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ 'bytesreadrate': self.module.params.get('disk_bytes_read_rate'),
+ 'byteswriterate': self.module.params.get('disk_bytes_write_rate'),
+ 'cpunumber': self.module.params.get('cpu_number'),
+ 'cpuspeed': self.module.params.get('cpu_speed'),
+ 'customizediops': self.module.params.get('is_iops_customized'),
+ 'deploymentplanner': self.module.params.get('deployment_planner'),
+ 'domainid': self.get_domain(key='id'),
+ 'hosttags': self.module.params.get('host_tags'),
+ 'hypervisorsnapshotreserve': self.module.params.get('hypervisor_snapshot_reserve'),
+ 'iopsreadrate': self.module.params.get('disk_iops_read_rate'),
+ 'iopswriterate': self.module.params.get('disk_iops_write_rate'),
+ 'maxiops': self.module.params.get('disk_iops_max'),
+ 'miniops': self.module.params.get('disk_iops_min'),
+ 'issystem': is_system,
+ 'isvolatile': self.module.params.get('is_volatile'),
+ 'memory': self.module.params.get('memory'),
+ 'networkrate': self.module.params.get('network_rate'),
+ 'offerha': self.module.params.get('offer_ha'),
+ 'provisioningtype': self.module.params.get('provisioning_type'),
+ 'serviceofferingdetails': self.module.params.get('service_offering_details'),
+ 'storagetype': self.module.params.get('storage_type'),
+ 'systemvmtype': system_vm_type,
+ 'tags': self.module.params.get('storage_tags'),
+ 'limitcpuuse': self.module.params.get('limit_cpu_usage'),
+ 'customized': self.module.params.get('is_customized')
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createServiceOffering', **args)
+ service_offering = res['serviceoffering']
+ return service_offering
+
+ def _update_offering(self, service_offering):
+ args = {
+ 'id': service_offering['id'],
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ }
+ if self.has_changed(args, service_offering):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('updateServiceOffering', **args)
+ service_offering = res['serviceoffering']
+ return service_offering
+
+ def get_result(self, service_offering):
+ super(AnsibleCloudStackServiceOffering, self).get_result(service_offering)
+ if service_offering:
+ if 'hosttags' in service_offering:
+ self.result['host_tags'] = service_offering['hosttags'].split(',') or [service_offering['hosttags']]
+
+ # Prevent confusion, the api returns a tags key for storage tags.
+ if 'tags' in service_offering:
+ self.result['storage_tags'] = service_offering['tags'].split(',') or [service_offering['tags']]
+ if 'tags' in self.result:
+ del self.result['tags']
+
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ display_text=dict(),
+ cpu_number=dict(type='int'),
+ cpu_speed=dict(type='int'),
+ limit_cpu_usage=dict(type='bool'),
+ deployment_planner=dict(),
+ domain=dict(),
+ host_tags=dict(type='list', elements='str', aliases=['host_tag']),
+ hypervisor_snapshot_reserve=dict(type='int'),
+ disk_bytes_read_rate=dict(type='int', aliases=['bytes_read_rate']),
+ disk_bytes_write_rate=dict(type='int', aliases=['bytes_write_rate']),
+ disk_iops_read_rate=dict(type='int'),
+ disk_iops_write_rate=dict(type='int'),
+ disk_iops_max=dict(type='int'),
+ disk_iops_min=dict(type='int'),
+ is_system=dict(type='bool', default=False),
+ is_volatile=dict(type='bool'),
+ is_iops_customized=dict(type='bool', aliases=['disk_iops_customized']),
+ memory=dict(type='int'),
+ network_rate=dict(type='int'),
+ offer_ha=dict(type='bool'),
+ provisioning_type=dict(choices=['thin', 'sparse', 'fat']),
+ service_offering_details=dict(type='list', elements='dict'),
+ storage_type=dict(choices=['local', 'shared']),
+ system_vm_type=dict(choices=['domainrouter', 'consoleproxy', 'secondarystoragevm']),
+ storage_tags=dict(type='list', elements='str', aliases=['storage_tag']),
+ state=dict(choices=['present', 'absent'], default='present'),
+ is_customized=dict(type='bool'),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_so = AnsibleCloudStackServiceOffering(module)
+
+ state = module.params.get('state')
+ if state == "absent":
+ service_offering = acs_so.absent_service_offering()
+ else:
+ service_offering = acs_so.present_service_offering()
+
+ result = acs_so.get_result(service_offering)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_snapshot_policy.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_snapshot_policy.py
new file mode 100644
index 00000000..bd11f367
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_snapshot_policy.py
@@ -0,0 +1,349 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_snapshot_policy
+short_description: Manages volume snapshot policies on Apache CloudStack based clouds.
+description:
+ - Create, update and delete volume snapshot policies.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ volume:
+ description:
+ - Name of the volume.
+ - Either I(volume) or I(vm) is required.
+ type: str
+ volume_type:
+ description:
+ - Type of the volume.
+ type: str
+ choices:
+ - DATADISK
+ - ROOT
+ vm:
+ description:
+ - Name of the instance to select the volume from.
+ - Use I(volume_type) if VM has a DATADISK and ROOT volume.
+ - In case of I(volume_type=DATADISK), additionally use I(device_id) if VM has more than one DATADISK volume.
+ - Either I(volume) or I(vm) is required.
+ type: str
+ device_id:
+ description:
+ - ID of the device on a VM the volume is attached to.
+ - This will only be considered if VM has multiple DATADISK volumes.
+ type: int
+ vpc:
+ description:
+ - Name of the vpc the instance is deployed in.
+ type: str
+ interval_type:
+ description:
+ - Interval of the snapshot.
+ type: str
+ default: daily
+ choices: [ hourly, daily, weekly, monthly ]
+ aliases: [ interval ]
+ max_snaps:
+ description:
+ - Max number of snapshots.
+ type: int
+ default: 8
+ aliases: [ max ]
+ schedule:
+ description:
+ - Time the snapshot is scheduled. Required if I(state=present).
+ - 'Format for I(interval_type=HOURLY): C(MM)'
+ - 'Format for I(interval_type=DAILY): C(MM:HH)'
+ - 'Format for I(interval_type=WEEKLY): C(MM:HH:DD (1-7))'
+ - 'Format for I(interval_type=MONTHLY): C(MM:HH:DD (1-28))'
+ type: str
+ time_zone:
+ description:
+ - Specifies a timezone for this command.
+ type: str
+ default: UTC
+ aliases: [ timezone ]
+ state:
+ description:
+ - State of the snapshot policy.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ domain:
+ description:
+ - Domain the volume is related to.
+ type: str
+ account:
+ description:
+ - Account the volume is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the volume is related to.
+ type: str
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: ensure a snapshot policy daily at 1h00 UTC
+ ngine_io.cloudstack.cs_snapshot_policy:
+ volume: ROOT-478
+ schedule: '00:1'
+ max_snaps: 3
+
+- name: ensure a snapshot policy daily at 1h00 UTC on the second DATADISK of VM web-01
+ ngine_io.cloudstack.cs_snapshot_policy:
+ vm: web-01
+ volume_type: DATADISK
+ device_id: 2
+ schedule: '00:1'
+ max_snaps: 3
+
+- name: ensure a snapshot policy hourly at minute 5 UTC
+ ngine_io.cloudstack.cs_snapshot_policy:
+ volume: ROOT-478
+ schedule: '5'
+ interval_type: hourly
+ max_snaps: 1
+
+- name: ensure a snapshot policy weekly on Sunday at 05h00, TZ Europe/Zurich
+ ngine_io.cloudstack.cs_snapshot_policy:
+ volume: ROOT-478
+ schedule: '00:5:1'
+ interval_type: weekly
+ max_snaps: 1
+ time_zone: 'Europe/Zurich'
+
+- name: ensure a snapshot policy is absent
+ ngine_io.cloudstack.cs_snapshot_policy:
+ volume: ROOT-478
+ interval_type: hourly
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the snapshot policy.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+interval_type:
+ description: interval type of the snapshot policy.
+ returned: success
+ type: str
+ sample: daily
+schedule:
+ description: schedule of the snapshot policy.
+ returned: success
+ type: str
+ sample:
+max_snaps:
+ description: maximum number of snapshots retained.
+ returned: success
+ type: int
+ sample: 10
+time_zone:
+ description: the time zone of the snapshot policy.
+ returned: success
+ type: str
+ sample: Etc/UTC
+volume:
+ description: the volume of the snapshot policy.
+ returned: success
+ type: str
+ sample: Etc/UTC
+zone:
+ description: Name of zone the volume is related to.
+ returned: success
+ type: str
+ sample: ch-gva-2
+project:
+ description: Name of project the volume is related to.
+ returned: success
+ type: str
+ sample: Production
+account:
+ description: Account the volume is related to.
+ returned: success
+ type: str
+ sample: example account
+domain:
+ description: Domain the volume is related to.
+ returned: success
+ type: str
+ sample: example domain
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackSnapshotPolicy(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackSnapshotPolicy, self).__init__(module)
+ self.returns = {
+ 'schedule': 'schedule',
+ 'timezone': 'time_zone',
+ 'maxsnaps': 'max_snaps',
+ }
+ self.interval_types = {
+ 'hourly': 0,
+ 'daily': 1,
+ 'weekly': 2,
+ 'monthly': 3,
+ }
+ self.volume = None
+
+ def get_interval_type(self):
+ interval_type = self.module.params.get('interval_type')
+ return self.interval_types[interval_type]
+
+ def get_volume(self, key=None):
+ if self.volume:
+ return self._get_by_key(key, self.volume)
+
+ args = {
+ 'name': self.module.params.get('volume'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'virtualmachineid': self.get_vm(key='id', filter_zone=False),
+ 'type': self.module.params.get('volume_type'),
+ }
+ volumes = self.query_api('listVolumes', **args)
+ if volumes:
+ if volumes['count'] > 1:
+ device_id = self.module.params.get('device_id')
+ if not device_id:
+ self.module.fail_json(msg="Found more then 1 volume: combine params 'vm', 'volume_type', 'device_id' and/or 'volume' to select the volume")
+ else:
+ for v in volumes['volume']:
+ if v.get('deviceid') == device_id:
+ self.volume = v
+ return self._get_by_key(key, self.volume)
+ self.module.fail_json(msg="No volume found with device id %s" % device_id)
+ self.volume = volumes['volume'][0]
+ return self._get_by_key(key, self.volume)
+ return None
+
+ def get_snapshot_policy(self):
+ args = {
+ 'volumeid': self.get_volume(key='id')
+ }
+ policies = self.query_api('listSnapshotPolicies', **args)
+ if policies:
+ for policy in policies['snapshotpolicy']:
+ if policy['intervaltype'] == self.get_interval_type():
+ return policy
+ return None
+
+ def present_snapshot_policy(self):
+ required_params = [
+ 'schedule',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ policy = self.get_snapshot_policy()
+ args = {
+ 'id': policy.get('id') if policy else None,
+ 'intervaltype': self.module.params.get('interval_type'),
+ 'schedule': self.module.params.get('schedule'),
+ 'maxsnaps': self.module.params.get('max_snaps'),
+ 'timezone': self.module.params.get('time_zone'),
+ 'volumeid': self.get_volume(key='id')
+ }
+ if not policy or (policy and self.has_changed(policy, args, only_keys=['schedule', 'maxsnaps', 'timezone'])):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('createSnapshotPolicy', **args)
+ policy = res['snapshotpolicy']
+ return policy
+
+ def absent_snapshot_policy(self):
+ policy = self.get_snapshot_policy()
+ if policy:
+ self.result['changed'] = True
+ args = {
+ 'id': policy['id']
+ }
+ if not self.module.check_mode:
+ self.query_api('deleteSnapshotPolicies', **args)
+ return policy
+
+ def get_result(self, policy):
+ super(AnsibleCloudStackSnapshotPolicy, self).get_result(policy)
+ if policy and 'intervaltype' in policy:
+ for key, value in self.interval_types.items():
+ if value == policy['intervaltype']:
+ self.result['interval_type'] = key
+ break
+ volume = self.get_volume()
+ if volume:
+ volume_results = {
+ 'volume': volume.get('name'),
+ 'zone': volume.get('zonename'),
+ 'project': volume.get('project'),
+ 'account': volume.get('account'),
+ 'domain': volume.get('domain'),
+ }
+ self.result.update(volume_results)
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ volume=dict(),
+ volume_type=dict(choices=['DATADISK', 'ROOT']),
+ vm=dict(),
+ device_id=dict(type='int'),
+ vpc=dict(),
+ interval_type=dict(default='daily', choices=['hourly', 'daily', 'weekly', 'monthly'], aliases=['interval']),
+ schedule=dict(),
+ time_zone=dict(default='UTC', aliases=['timezone']),
+ max_snaps=dict(type='int', default=8, aliases=['max']),
+ state=dict(choices=['present', 'absent'], default='present'),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ required_one_of=(
+ ['vm', 'volume'],
+ ),
+ supports_check_mode=True
+ )
+
+ acs_snapshot_policy = AnsibleCloudStackSnapshotPolicy(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ policy = acs_snapshot_policy.absent_snapshot_policy()
+ else:
+ policy = acs_snapshot_policy.present_snapshot_policy()
+
+ result = acs_snapshot_policy.get_result(policy)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_sshkeypair.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_sshkeypair.py
new file mode 100644
index 00000000..3e32171c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_sshkeypair.py
@@ -0,0 +1,261 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_sshkeypair
+short_description: Manages SSH keys on Apache CloudStack based clouds.
+description:
+ - Create, register and remove SSH keys.
+ - If no key was found and no public key was provided and a new SSH
+ private/public key pair will be created and the private key will be returned.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of public key.
+ type: str
+ required: true
+ domain:
+ description:
+ - Domain the public key is related to.
+ type: str
+ account:
+ description:
+ - Account the public key is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the public key to be registered in.
+ type: str
+ state:
+ description:
+ - State of the public key.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ public_key:
+ description:
+ - String of the public key.
+ type: str
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: create a new private / public key pair
+ ngine_io.cloudstack.cs_sshkeypair:
+ name: linus@example.com
+ register: key
+
+- debug:
+ msg: 'Private key is {{ key.private_key }}'
+
+- name: remove a public key by its name
+ ngine_io.cloudstack.cs_sshkeypair:
+ name: linus@example.com
+ state: absent
+
+- name: register your existing local public key
+ ngine_io.cloudstack.cs_sshkeypair:
+ name: linus@example.com
+ public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the SSH public key.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+name:
+ description: Name of the SSH public key.
+ returned: success
+ type: str
+ sample: linus@example.com
+fingerprint:
+ description: Fingerprint of the SSH public key.
+ returned: success
+ type: str
+ sample: "86:5e:a3:e8:bd:95:7b:07:7c:c2:5c:f7:ad:8b:09:28"
+private_key:
+ description: Private key of generated SSH keypair.
+ returned: changed
+ type: str
+ sample: "-----BEGIN RSA PRIVATE KEY-----\nMII...8tO\n-----END RSA PRIVATE KEY-----\n"
+'''
+
+import traceback
+
+SSHPUBKEYS_IMP_ERR = None
+try:
+ import sshpubkeys
+ HAS_LIB_SSHPUBKEYS = True
+except ImportError:
+ SSHPUBKEYS_IMP_ERR = traceback.format_exc()
+ HAS_LIB_SSHPUBKEYS = False
+
+from ansible.module_utils.basic import AnsibleModule, missing_required_lib
+from ansible.module_utils._text import to_native
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_required_together,
+ cs_argument_spec
+)
+
+
+class AnsibleCloudStackSshKey(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackSshKey, self).__init__(module)
+ self.returns = {
+ 'privatekey': 'private_key',
+ 'fingerprint': 'fingerprint',
+ }
+ self.ssh_key = None
+
+ def register_ssh_key(self, public_key):
+ ssh_key = self.get_ssh_key()
+ args = self._get_common_args()
+ name = self.module.params.get('name')
+
+ res = None
+ if not ssh_key:
+ self.result['changed'] = True
+ args['publickey'] = public_key
+ if not self.module.check_mode:
+ args['name'] = name
+ res = self.query_api('registerSSHKeyPair', **args)
+ else:
+ fingerprint = self._get_ssh_fingerprint(public_key)
+ if ssh_key['fingerprint'] != fingerprint:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ # delete the ssh key with matching name but wrong fingerprint
+ args['name'] = name
+ self.query_api('deleteSSHKeyPair', **args)
+
+ elif ssh_key['name'].lower() != name.lower():
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ # delete the ssh key with matching fingerprint but wrong name
+ args['name'] = ssh_key['name']
+ self.query_api('deleteSSHKeyPair', **args)
+ # First match for key retrievement will be the fingerprint.
+ # We need to make another lookup if there is a key with identical name.
+ self.ssh_key = None
+ ssh_key = self.get_ssh_key()
+ if ssh_key and ssh_key['fingerprint'] != fingerprint:
+ args['name'] = name
+ self.query_api('deleteSSHKeyPair', **args)
+
+ if not self.module.check_mode and self.result['changed']:
+ args['publickey'] = public_key
+ args['name'] = name
+ res = self.query_api('registerSSHKeyPair', **args)
+
+ if res and 'keypair' in res:
+ ssh_key = res['keypair']
+
+ return ssh_key
+
+ def create_ssh_key(self):
+ ssh_key = self.get_ssh_key()
+ if not ssh_key:
+ self.result['changed'] = True
+ args = self._get_common_args()
+ args['name'] = self.module.params.get('name')
+ if not self.module.check_mode:
+ res = self.query_api('createSSHKeyPair', **args)
+ ssh_key = res['keypair']
+ return ssh_key
+
+ def remove_ssh_key(self, name=None):
+ ssh_key = self.get_ssh_key()
+ if ssh_key:
+ self.result['changed'] = True
+ args = self._get_common_args()
+ args['name'] = name or self.module.params.get('name')
+ if not self.module.check_mode:
+ self.query_api('deleteSSHKeyPair', **args)
+ return ssh_key
+
+ def _get_common_args(self):
+ return {
+ 'domainid': self.get_domain('id'),
+ 'account': self.get_account('name'),
+ 'projectid': self.get_project('id')
+ }
+
+ def get_ssh_key(self):
+ if not self.ssh_key:
+ public_key = self.module.params.get('public_key')
+ if public_key:
+ # Query by fingerprint of the public key
+ args_fingerprint = self._get_common_args()
+ args_fingerprint['fingerprint'] = self._get_ssh_fingerprint(public_key)
+ ssh_keys = self.query_api('listSSHKeyPairs', **args_fingerprint)
+ if ssh_keys and 'sshkeypair' in ssh_keys:
+ self.ssh_key = ssh_keys['sshkeypair'][0]
+ # When key has not been found by fingerprint, use the name
+ if not self.ssh_key:
+ args_name = self._get_common_args()
+ args_name['name'] = self.module.params.get('name')
+ ssh_keys = self.query_api('listSSHKeyPairs', **args_name)
+ if ssh_keys and 'sshkeypair' in ssh_keys:
+ self.ssh_key = ssh_keys['sshkeypair'][0]
+ return self.ssh_key
+
+ def _get_ssh_fingerprint(self, public_key):
+ key = sshpubkeys.SSHKey(public_key)
+ if hasattr(key, 'hash_md5'):
+ return key.hash_md5().replace(to_native('MD5:'), to_native(''))
+ return key.hash()
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ public_key=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ if not HAS_LIB_SSHPUBKEYS:
+ module.fail_json(msg=missing_required_lib("sshpubkeys"), exception=SSHPUBKEYS_IMP_ERR)
+
+ acs_sshkey = AnsibleCloudStackSshKey(module)
+ state = module.params.get('state')
+ if state in ['absent']:
+ ssh_key = acs_sshkey.remove_ssh_key()
+ else:
+ public_key = module.params.get('public_key')
+ if public_key:
+ ssh_key = acs_sshkey.register_ssh_key(public_key)
+ else:
+ ssh_key = acs_sshkey.create_ssh_key()
+
+ result = acs_sshkey.get_result(ssh_key)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_staticnat.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_staticnat.py
new file mode 100644
index 00000000..5d223715
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_staticnat.py
@@ -0,0 +1,249 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_staticnat
+short_description: Manages static NATs on Apache CloudStack based clouds.
+description:
+ - Create, update and remove static NATs.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ ip_address:
+ description:
+ - Public IP address the static NAT is assigned to.
+ type: str
+ required: true
+ vm:
+ description:
+ - Name of virtual machine which we make the static NAT for.
+ - Required if I(state=present).
+ type: str
+ vm_guest_ip:
+ description:
+ - VM guest NIC secondary IP address for the static NAT.
+ type: str
+ network:
+ description:
+ - Network the IP address is related to.
+ type: str
+ vpc:
+ description:
+ - VPC the network related to.
+ type: str
+ state:
+ description:
+ - State of the static NAT.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ domain:
+ description:
+ - Domain the static NAT is related to.
+ type: str
+ account:
+ description:
+ - Account the static NAT is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the static NAT is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the virtual machine is in.
+ - If not set, default zone is used.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a static NAT for IP 1.2.3.4 to web01
+ ngine_io.cloudstack.cs_staticnat:
+ ip_address: 1.2.3.4
+ vm: web01
+
+- name: Remove a static NAT
+ ngine_io.cloudstack.cs_staticnat:
+ ip_address: 1.2.3.4
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the ip_address.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+ip_address:
+ description: Public IP address.
+ returned: success
+ type: str
+ sample: 1.2.3.4
+vm_name:
+ description: Name of the virtual machine.
+ returned: success
+ type: str
+ sample: web-01
+vm_display_name:
+ description: Display name of the virtual machine.
+ returned: success
+ type: str
+ sample: web-01
+vm_guest_ip:
+ description: IP of the virtual machine.
+ returned: success
+ type: str
+ sample: 10.101.65.152
+zone:
+ description: Name of zone the static NAT is related to.
+ returned: success
+ type: str
+ sample: ch-gva-2
+project:
+ description: Name of project the static NAT is related to.
+ returned: success
+ type: str
+ sample: Production
+account:
+ description: Account the static NAT is related to.
+ returned: success
+ type: str
+ sample: example account
+domain:
+ description: Domain the static NAT is related to.
+ returned: success
+ type: str
+ sample: example domain
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackStaticNat(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackStaticNat, self).__init__(module)
+ self.returns = {
+ 'virtualmachinedisplayname': 'vm_display_name',
+ 'virtualmachinename': 'vm_name',
+ 'ipaddress': 'ip_address',
+ 'vmipaddress': 'vm_guest_ip',
+ }
+
+ def create_static_nat(self, ip_address):
+ self.result['changed'] = True
+ args = {
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'ipaddressid': ip_address['id'],
+ 'vmguestip': self.get_vm_guest_ip(),
+ 'networkid': self.get_network(key='id')
+ }
+ if not self.module.check_mode:
+ self.query_api('enableStaticNat', **args)
+
+ # reset ip address and query new values
+ self.ip_address = None
+ ip_address = self.get_ip_address()
+ return ip_address
+
+ def update_static_nat(self, ip_address):
+ args = {
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'ipaddressid': ip_address['id'],
+ 'vmguestip': self.get_vm_guest_ip(),
+ 'networkid': self.get_network(key='id')
+ }
+ # make an alias, so we can use has_changed()
+ ip_address['vmguestip'] = ip_address['vmipaddress']
+ if self.has_changed(args, ip_address, ['vmguestip', 'virtualmachineid']):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('disableStaticNat', ipaddressid=ip_address['id'])
+ self.poll_job(res, 'staticnat')
+
+ self.query_api('enableStaticNat', **args)
+
+ # reset ip address and query new values
+ self.ip_address = None
+ ip_address = self.get_ip_address()
+ return ip_address
+
+ def present_static_nat(self):
+ ip_address = self.get_ip_address()
+ if not ip_address['isstaticnat']:
+ ip_address = self.create_static_nat(ip_address)
+ else:
+ ip_address = self.update_static_nat(ip_address)
+ return ip_address
+
+ def absent_static_nat(self):
+ ip_address = self.get_ip_address()
+ if ip_address['isstaticnat']:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('disableStaticNat', ipaddressid=ip_address['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'staticnat')
+ return ip_address
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ ip_address=dict(required=True),
+ vm=dict(),
+ vm_guest_ip=dict(),
+ network=dict(),
+ vpc=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ zone=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_static_nat = AnsibleCloudStackStaticNat(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ ip_address = acs_static_nat.absent_static_nat()
+ else:
+ ip_address = acs_static_nat.present_static_nat()
+
+ result = acs_static_nat.get_result(ip_address)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_storage_pool.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_storage_pool.py
new file mode 100644
index 00000000..e4034587
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_storage_pool.py
@@ -0,0 +1,489 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, Netservers Ltd. <support@netservers.co.uk>
+# Copyright (c) 2017, 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: cs_storage_pool
+short_description: Manages Primary Storage Pools on Apache CloudStack based clouds.
+description:
+ - Create, update, put into maintenance, disable, enable and remove storage pools.
+author:
+ - Netservers Ltd. (@netservers)
+ - René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the storage pool.
+ type: str
+ required: true
+ zone:
+ description:
+ - Name of the zone in which the host should be deployed.
+ - If not set, default zone is used.
+ type: str
+ storage_url:
+ description:
+ - URL of the storage pool.
+ - Required if I(state=present).
+ type: str
+ pod:
+ description:
+ - Name of the pod.
+ type: str
+ cluster:
+ description:
+ - Name of the cluster.
+ type: str
+ scope:
+ description:
+ - The scope of the storage pool.
+ - Defaults to cluster when C(cluster) is provided, otherwise zone.
+ type: str
+ choices: [ cluster, zone ]
+ managed:
+ description:
+ - Whether the storage pool should be managed by CloudStack.
+ - Only considered on creation.
+ type: bool
+ hypervisor:
+ description:
+ - Required when creating a zone scoped pool.
+ - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator).
+ type: str
+ storage_tags:
+ description:
+ - Tags associated with this storage pool.
+ type: list
+ elements: str
+ aliases: [ storage_tag ]
+ provider:
+ description:
+ - Name of the storage provider e.g. SolidFire, SolidFireShared, DefaultPrimary, CloudByte.
+ type: str
+ default: DefaultPrimary
+ capacity_bytes:
+ description:
+ - Bytes CloudStack can provision from this storage pool.
+ type: int
+ capacity_iops:
+ description:
+ - Bytes CloudStack can provision from this storage pool.
+ type: int
+ allocation_state:
+ description:
+ - Allocation state of the storage pool.
+ type: str
+ choices: [ enabled, disabled, maintenance ]
+ state:
+ description:
+ - State of the storage pool.
+ type: str
+ default: present
+ choices: [ present, absent ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: ensure a zone scoped storage_pool is present
+ ngine_io.cloudstack.cs_storage_pool:
+ zone: zone01
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ provider: DefaultPrimary
+ name: Ceph RBD
+ scope: zone
+ hypervisor: KVM
+
+- name: ensure a cluster scoped storage_pool is disabled
+ ngine_io.cloudstack.cs_storage_pool:
+ name: Ceph RBD
+ zone: zone01
+ cluster: cluster01
+ pod: pod01
+ storage_url: rbd://admin:SECRET@ceph-the-mons.domain/poolname
+ provider: DefaultPrimary
+ scope: cluster
+ allocation_state: disabled
+
+- name: ensure a cluster scoped storage_pool is in maintenance
+ ngine_io.cloudstack.cs_storage_pool:
+ name: Ceph RBD
+ zone: zone01
+ cluster: cluster01
+ pod: pod01
+ storage_url: rbd://admin:SECRET@ceph-the-mons.domain/poolname
+ provider: DefaultPrimary
+ scope: cluster
+ allocation_state: maintenance
+
+- name: ensure a storage_pool is absent
+ ngine_io.cloudstack.cs_storage_pool:
+ name: Ceph RBD
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the pool.
+ returned: success
+ type: str
+ sample: a3fca65a-7db1-4891-b97c-48806a978a96
+created:
+ description: Date of the pool was created.
+ returned: success
+ type: str
+ sample: 2014-12-01T14:57:57+0100
+capacity_iops:
+ description: IOPS CloudStack can provision from this storage pool
+ returned: when available
+ type: int
+ sample: 60000
+zone:
+ description: The name of the zone.
+ returned: success
+ type: str
+ sample: Zone01
+cluster:
+ description: The name of the cluster.
+ returned: when scope is cluster
+ type: str
+ sample: Cluster01
+pod:
+ description: The name of the pod.
+ returned: when scope is cluster
+ type: str
+ sample: Cluster01
+disk_size_allocated:
+ description: The pool's currently allocated disk space.
+ returned: success
+ type: int
+ sample: 2443517624320
+disk_size_total:
+ description: The total size of the pool.
+ returned: success
+ type: int
+ sample: 3915055693824
+disk_size_used:
+ description: The pool's currently used disk size.
+ returned: success
+ type: int
+ sample: 1040862622180
+scope:
+ description: The scope of the storage pool.
+ returned: success
+ type: str
+ sample: cluster
+hypervisor:
+ description: Hypervisor related to this storage pool.
+ returned: when available
+ type: str
+ sample: KVM
+state:
+ description: The state of the storage pool as returned by the API.
+ returned: success
+ type: str
+ sample: Up
+allocation_state:
+ description: The state of the storage pool.
+ returned: success
+ type: str
+ sample: enabled
+path:
+ description: The storage pool path used in the storage_url.
+ returned: success
+ type: str
+ sample: poolname
+overprovision_factor:
+ description: The overprovision factor of the storage pool.
+ returned: success
+ type: str
+ sample: 2.0
+suitable_for_migration:
+ description: Whether the storage pool is suitable to migrate a volume or not.
+ returned: success
+ type: bool
+ sample: false
+storage_capabilities:
+ description: Capabilities of the storage pool.
+ returned: success
+ type: dict
+ sample: {"VOLUME_SNAPSHOT_QUIESCEVM": "false"}
+storage_tags:
+ description: the tags for the storage pool.
+ returned: success
+ type: list
+ sample: ["perf", "ssd"]
+'''
+
+# import cloudstack common
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackStoragePool(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackStoragePool, self).__init__(module)
+ self.returns = {
+ 'capacityiops': 'capacity_iops',
+ 'podname': 'pod',
+ 'clustername': 'cluster',
+ 'disksizeallocated': 'disk_size_allocated',
+ 'disksizetotal': 'disk_size_total',
+ 'disksizeused': 'disk_size_used',
+ 'scope': 'scope',
+ 'hypervisor': 'hypervisor',
+ 'type': 'type',
+ 'ip_address': 'ipaddress',
+ 'path': 'path',
+ 'overprovisionfactor': 'overprovision_factor',
+ 'storagecapabilities': 'storage_capabilities',
+ 'suitableformigration': 'suitable_for_migration',
+ }
+ self.allocation_states = {
+ # Host state: param state
+ 'Up': 'enabled',
+ 'Disabled': 'disabled',
+ 'Maintenance': 'maintenance',
+ }
+ self.storage_pool = None
+
+ def _get_common_args(self):
+ return {
+ 'name': self.module.params.get('name'),
+ 'url': self.module.params.get('storage_url'),
+ 'zoneid': self.get_zone(key='id'),
+ 'provider': self.get_storage_provider(),
+ 'scope': self.module.params.get('scope'),
+ 'hypervisor': self.module.params.get('hypervisor'),
+ 'capacitybytes': self.module.params.get('capacity_bytes'),
+ 'capacityiops': self.module.params.get('capacity_iops'),
+ }
+
+ def _allocation_state_enabled_disabled_changed(self, pool, allocation_state):
+ if allocation_state in ['enabled', 'disabled']:
+ for pool_state, param_state in self.allocation_states.items():
+ if pool_state == pool['state'] and allocation_state != param_state:
+ return True
+ return False
+
+ def _handle_allocation_state(self, pool, state=None):
+ allocation_state = state or self.module.params.get('allocation_state')
+ if not allocation_state:
+ return pool
+
+ if self.allocation_states.get(pool['state']) == allocation_state:
+ return pool
+
+ # Cancel maintenance if target state is enabled/disabled
+ elif allocation_state in ['enabled', 'disabled']:
+ pool = self._cancel_maintenance(pool)
+ pool = self._update_storage_pool(pool=pool, allocation_state=allocation_state)
+
+ # Only an enabled host can put in maintenance
+ elif allocation_state == 'maintenance':
+ pool = self._update_storage_pool(pool=pool, allocation_state='enabled')
+ pool = self._enable_maintenance(pool=pool)
+
+ return pool
+
+ def _create_storage_pool(self):
+ args = self._get_common_args()
+ args.update({
+ 'clusterid': self.get_cluster(key='id'),
+ 'podid': self.get_pod(key='id'),
+ 'managed': self.module.params.get('managed'),
+ })
+
+ scope = self.module.params.get('scope')
+ if scope is None:
+ args['scope'] = 'cluster' if args['clusterid'] else 'zone'
+
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('createStoragePool', **args)
+ return res['storagepool']
+
+ def _update_storage_pool(self, pool, allocation_state=None):
+ args = {
+ 'id': pool['id'],
+ 'capacitybytes': self.module.params.get('capacity_bytes'),
+ 'capacityiops': self.module.params.get('capacity_iops'),
+ 'tags': self.get_storage_tags(),
+ }
+
+ if self.has_changed(args, pool) or self._allocation_state_enabled_disabled_changed(pool, allocation_state):
+ self.result['changed'] = True
+ args['enabled'] = allocation_state == 'enabled' if allocation_state in ['enabled', 'disabled'] else None
+ if not self.module.check_mode:
+ res = self.query_api('updateStoragePool', **args)
+ pool = res['storagepool']
+ return pool
+
+ def _enable_maintenance(self, pool):
+ if pool['state'].lower() != "maintenance":
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('enableStorageMaintenance', id=pool['id'])
+ pool = self.poll_job(res, 'storagepool')
+ return pool
+
+ def _cancel_maintenance(self, pool):
+ if pool['state'].lower() == "maintenance":
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('cancelStorageMaintenance', id=pool['id'])
+ pool = self.poll_job(res, 'storagepool')
+ return pool
+
+ def get_storage_tags(self):
+ storage_tags = self.module.params.get('storage_tags')
+ if storage_tags is None:
+ return None
+ return ','.join(storage_tags)
+
+ def get_storage_pool(self, key=None):
+ if self.storage_pool is None:
+ zoneid = self.get_zone(key='id')
+ clusterid = self.get_cluster(key='id')
+ podid = self.get_pod(key='id')
+
+ args = {
+ 'zoneid': zoneid,
+ 'podid': podid,
+ 'clusterid': clusterid,
+ 'name': self.module.params.get('name'),
+ }
+
+ res = self.query_api('listStoragePools', **args)
+ if 'storagepool' not in res:
+ return None
+
+ self.storage_pool = res['storagepool'][0]
+
+ return self.storage_pool
+
+ def present_storage_pool(self):
+ pool = self.get_storage_pool()
+ if pool:
+ pool = self._update_storage_pool(pool=pool)
+ else:
+ pool = self._create_storage_pool()
+
+ if pool:
+ pool = self._handle_allocation_state(pool=pool)
+
+ return pool
+
+ def absent_storage_pool(self):
+ pool = self.get_storage_pool()
+ if pool:
+ self.result['changed'] = True
+
+ args = {
+ 'id': pool['id'],
+ }
+ if not self.module.check_mode:
+ # Only a pool in maintenance can be deleted
+ self._handle_allocation_state(pool=pool, state='maintenance')
+ self.query_api('deleteStoragePool', **args)
+ return pool
+
+ def get_storage_provider(self, type="primary"):
+ args = {
+ 'type': type,
+ }
+ provider = self.module.params.get('provider')
+ storage_providers = self.query_api('listStorageProviders', **args)
+ for sp in storage_providers.get('dataStoreProvider') or []:
+ if sp['name'].lower() == provider.lower():
+ return provider
+ self.fail_json(msg="Storage provider %s not found" % provider)
+
+ def get_cluster(self, key=None):
+ cluster = self.module.params.get('cluster')
+ if not cluster:
+ return None
+
+ args = {
+ 'name': cluster,
+ 'zoneid': self.get_zone(key='id'),
+ }
+
+ clusters = self.query_api('listClusters', **args)
+ if clusters:
+ return self._get_by_key(key, clusters['cluster'][0])
+
+ self.fail_json(msg="Cluster %s not found" % cluster)
+
+ def get_result(self, pool):
+ super(AnsibleCloudStackStoragePool, self).get_result(pool)
+ if pool:
+ self.result['storage_url'] = "%s://%s/%s" % (pool['type'], pool['ipaddress'], pool['path'])
+ self.result['scope'] = pool['scope'].lower()
+ self.result['storage_tags'] = pool['tags'].split(',') if pool.get('tags') else []
+ self.result['allocation_state'] = self.allocation_states.get(pool['state'])
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ storage_url=dict(),
+ zone=dict(),
+ pod=dict(),
+ cluster=dict(),
+ scope=dict(choices=['zone', 'cluster']),
+ hypervisor=dict(),
+ provider=dict(default='DefaultPrimary'),
+ capacity_bytes=dict(type='int'),
+ capacity_iops=dict(type='int'),
+ managed=dict(type='bool'),
+ storage_tags=dict(type='list', elements='str', aliases=['storage_tag']),
+ allocation_state=dict(choices=['enabled', 'disabled', 'maintenance']),
+ state=dict(choices=['present', 'absent'], default='present'),
+ ))
+
+ required_together = cs_required_together()
+ required_together.extend([
+ ['pod', 'cluster'],
+ ])
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=required_together,
+ required_if=[
+ ('state', 'present', ['storage_url']),
+ ],
+ supports_check_mode=True
+ )
+
+ acs_storage_pool = AnsibleCloudStackStoragePool(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ pool = acs_storage_pool.absent_storage_pool()
+ else:
+ pool = acs_storage_pool.present_storage_pool()
+
+ result = acs_storage_pool.get_result(pool)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_template.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_template.py
new file mode 100644
index 00000000..16902595
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_template.py
@@ -0,0 +1,741 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_template
+short_description: Manages templates on Apache CloudStack based clouds.
+description:
+ - Register templates from an URL.
+ - Create templates from a ROOT volume of a stopped VM or its snapshot.
+ - Update, extract and delete templates.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the template.
+ type: str
+ required: true
+ url:
+ description:
+ - URL of where the template is hosted on I(state=present).
+ - URL to which the template would be extracted on I(state=extracted).
+ - Mutually exclusive with I(vm).
+ type: str
+ vm:
+ description:
+ - VM name the template will be created from its volume or alternatively from a snapshot.
+ - VM must be in stopped state if created from its volume.
+ - Mutually exclusive with I(url).
+ type: str
+ snapshot:
+ description:
+ - Name of the snapshot, created from the VM ROOT volume, the template will be created from.
+ - I(vm) is required together with this argument.
+ type: str
+ os_type:
+ description:
+ - OS type that best represents the OS of this template.
+ type: str
+ checksum:
+ description:
+ - The MD5 checksum value of this template.
+ - If set, we search by checksum instead of name.
+ type: str
+ is_public:
+ description:
+ - Register the template to be publicly available to all users.
+ - Only used if I(state) is C(present).
+ type: bool
+ is_featured:
+ description:
+ - Register the template to be featured.
+ - Only used if I(state) is C(present).
+ type: bool
+ is_dynamically_scalable:
+ description:
+ - Register the template having XS/VMware tools installed in order to support dynamic scaling of VM CPU/memory.
+ - Only used if I(state) is C(present).
+ type: bool
+ cross_zones:
+ description:
+ - Whether the template should be synced or removed across zones.
+ - Only used if I(state) is C(present) or C(absent).
+ default: no
+ type: bool
+ mode:
+ description:
+ - Mode for the template extraction.
+ - Only used if I(state=extracted).
+ type: str
+ default: http_download
+ choices: [ http_download, ftp_upload ]
+ domain:
+ description:
+ - Domain the template, snapshot or VM is related to.
+ type: str
+ account:
+ description:
+ - Account the template, snapshot or VM is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the template to be registered in.
+ type: str
+ zone:
+ description:
+ - Name of the zone you wish the template to be registered or deleted from.
+ - If not specified, first found zone will be used.
+ type: str
+ template_filter:
+ description:
+ - Name of the filter used to search for the template.
+ - The filter C(all) was added in 2.7.
+ type: str
+ default: self
+ choices: [ all, featured, self, selfexecutable, sharedexecutable, executable, community ]
+ template_find_options:
+ description:
+ - Options to find a template uniquely.
+ - More than one allowed.
+ type: list
+ elements: str
+ choices: [ display_text, checksum, cross_zones ]
+ aliases: [ template_find_option ]
+ default: []
+ hypervisor:
+ description:
+ - Name the hypervisor to be used for creating the new template.
+ - Relevant when using I(state=present).
+ - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator).
+ type: str
+ requires_hvm:
+ description:
+ - Whether the template requires HVM or not.
+ - Only considered while creating the template.
+ type: bool
+ password_enabled:
+ description:
+ - Enable template password reset support.
+ type: bool
+ template_tag:
+ description:
+ - The tag for this template.
+ type: str
+ sshkey_enabled:
+ description:
+ - True if the template supports the sshkey upload feature.
+ - Only considered if I(url) is used (API limitation).
+ type: bool
+ is_routing:
+ description:
+ - Sets the template type to routing, i.e. if template is used to deploy routers.
+ - Only considered if I(url) is used.
+ type: bool
+ format:
+ description:
+ - The format for the template.
+ - Only considered if I(state=present).
+ type: str
+ choices: [ QCOW2, RAW, VHD, OVA ]
+ is_extractable:
+ description:
+ - Allows the template or its derivatives to be extractable.
+ type: bool
+ details:
+ description:
+ - Template details in key/value pairs.
+ type: str
+ bits:
+ description:
+ - 32 or 64 bits support.
+ type: int
+ default: 64
+ choices: [ 32, 64 ]
+ display_text:
+ description:
+ - Display text of the template.
+ type: str
+ state:
+ description:
+ - State of the template.
+ type: str
+ default: present
+ choices: [ present, absent, extracted ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "To delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: register a systemvm template
+ ngine_io.cloudstack.cs_template:
+ name: systemvm-vmware-4.5
+ url: "http://packages.shapeblue.com/systemvmtemplate/4.5/systemvm64template-4.5-vmware.ova"
+ hypervisor: VMware
+ format: OVA
+ cross_zones: yes
+ os_type: Debian GNU/Linux 7(64-bit)
+
+- name: Create a template from a stopped virtual machine's volume
+ ngine_io.cloudstack.cs_template:
+ name: Debian 9 (64-bit) 20GB ({{ ansible_date_time.date }})
+ vm: debian-9-base-vm
+ os_type: Debian GNU/Linux 9 (64-bit)
+ zone: tokio-ix
+ password_enabled: yes
+ is_public: yes
+
+
+# Note: Use template_find_option(s) when a template name is not unique
+- name: Create a template from a stopped virtual machine's volume
+ ngine_io.cloudstack.cs_template:
+ name: Debian 9 (64-bit)
+ display_text: Debian 9 (64-bit) 20GB ({{ ansible_date_time.date }})
+ template_find_option: display_text
+ vm: debian-9-base-vm
+ os_type: Debian GNU/Linux 9 (64-bit)
+ zone: tokio-ix
+ password_enabled: yes
+ is_public: yes
+
+- name: create a template from a virtual machine's root volume snapshot
+ ngine_io.cloudstack.cs_template:
+ name: Debian 9 (64-bit) Snapshot ROOT-233_2015061509114
+ snapshot: ROOT-233_2015061509114
+ os_type: Debian GNU/Linux 9 (64-bit)
+ zone: tokio-ix
+ password_enabled: yes
+ is_public: yes
+
+- name: Remove a template
+ ngine_io.cloudstack.cs_template:
+ name: systemvm-4.2
+ cross_zones: yes
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the template or extracted object.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+name:
+ description: Name of the template or extracted object.
+ returned: success
+ type: str
+ sample: Debian 7 64-bit
+display_text:
+ description: Display text of the template.
+ returned: if available
+ type: str
+ sample: Debian 7.7 64-bit minimal 2015-03-19
+checksum:
+ description: MD5 checksum of the template.
+ returned: if available
+ type: str
+ sample: 0b31bccccb048d20b551f70830bb7ad0
+status:
+ description: Status of the template or extracted object.
+ returned: success
+ type: str
+ sample: Download Complete
+is_ready:
+ description: True if the template is ready to be deployed from.
+ returned: if available
+ type: bool
+ sample: true
+is_public:
+ description: True if the template is public.
+ returned: if available
+ type: bool
+ sample: true
+is_featured:
+ description: True if the template is featured.
+ returned: if available
+ type: bool
+ sample: true
+is_extractable:
+ description: True if the template is extractable.
+ returned: if available
+ type: bool
+ sample: true
+format:
+ description: Format of the template.
+ returned: if available
+ type: str
+ sample: OVA
+os_type:
+ description: Type of the OS.
+ returned: if available
+ type: str
+ sample: CentOS 6.5 (64-bit)
+password_enabled:
+ description: True if the reset password feature is enabled, false otherwise.
+ returned: if available
+ type: bool
+ sample: false
+sshkey_enabled:
+ description: true if template is sshkey enabled, false otherwise.
+ returned: if available
+ type: bool
+ sample: false
+cross_zones:
+ description: true if the template is managed across all zones, false otherwise.
+ returned: if available
+ type: bool
+ sample: false
+template_type:
+ description: Type of the template.
+ returned: if available
+ type: str
+ sample: USER
+created:
+ description: Date of registering.
+ returned: success
+ type: str
+ sample: 2015-03-29T14:57:06+0200
+template_tag:
+ description: Template tag related to this template.
+ returned: if available
+ type: str
+ sample: special
+hypervisor:
+ description: Hypervisor related to this template.
+ returned: if available
+ type: str
+ sample: VMware
+mode:
+ description: Mode of extraction
+ returned: on state=extracted
+ type: str
+ sample: http_download
+state:
+ description: State of the extracted template
+ returned: on state=extracted
+ type: str
+ sample: DOWNLOAD_URL_CREATED
+url:
+ description: Url to which the template is extracted to
+ returned: on state=extracted
+ type: str
+ sample: "http://1.2.3.4/userdata/eb307f13-4aca-45e8-b157-a414a14e6b04.ova"
+tags:
+ description: List of resource tags associated with the template.
+ returned: if available
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+zone:
+ description: Name of zone the template is registered in.
+ returned: success
+ type: str
+ sample: zuerich
+domain:
+ description: Domain the template is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the template is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project the template is related to.
+ returned: success
+ type: str
+ sample: Production
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackTemplate(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackTemplate, self).__init__(module)
+ self.returns = {
+ 'checksum': 'checksum',
+ 'status': 'status',
+ 'isready': 'is_ready',
+ 'templatetag': 'template_tag',
+ 'sshkeyenabled': 'sshkey_enabled',
+ 'passwordenabled': 'password_enabled',
+ 'templatetype': 'template_type',
+ 'ostypename': 'os_type',
+ 'crossZones': 'cross_zones',
+ 'format': 'format',
+ 'hypervisor': 'hypervisor',
+ 'url': 'url',
+ 'extractMode': 'mode',
+ 'state': 'state',
+ }
+
+ def _get_args(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ 'bits': self.module.params.get('bits'),
+ 'isdynamicallyscalable': self.module.params.get('is_dynamically_scalable'),
+ 'isextractable': self.module.params.get('is_extractable'),
+ 'isfeatured': self.module.params.get('is_featured'),
+ 'ispublic': self.module.params.get('is_public'),
+ 'passwordenabled': self.module.params.get('password_enabled'),
+ 'requireshvm': self.module.params.get('requires_hvm'),
+ 'templatetag': self.module.params.get('template_tag'),
+ 'ostypeid': self.get_os_type(key='id'),
+ }
+
+ if not args['ostypeid']:
+ self.module.fail_json(msg="Missing required arguments: os_type")
+
+ return args
+
+ def get_root_volume(self, key=None):
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'type': "ROOT"
+ }
+ volumes = self.query_api('listVolumes', **args)
+ if volumes:
+ return self._get_by_key(key, volumes['volume'][0])
+ self.module.fail_json(msg="Root volume for '%s' not found" % self.get_vm('name'))
+
+ def get_snapshot(self, key=None):
+ snapshot = self.module.params.get('snapshot')
+ if not snapshot:
+ return None
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'volumeid': self.get_root_volume('id'),
+ 'fetch_list': True,
+ }
+ snapshots = self.query_api('listSnapshots', **args)
+ if snapshots:
+ for s in snapshots:
+ if snapshot in [s['name'], s['id']]:
+ return self._get_by_key(key, s)
+ self.module.fail_json(msg="Snapshot '%s' not found" % snapshot)
+
+ def present_template(self):
+ template = self.get_template()
+ if template:
+ template = self.update_template(template)
+ elif self.module.params.get('url'):
+ template = self.register_template()
+ elif self.module.params.get('vm'):
+ template = self.create_template()
+ else:
+ self.fail_json(msg="one of the following is required on state=present: url, vm")
+ return template
+
+ def create_template(self):
+ template = None
+ self.result['changed'] = True
+
+ args = self._get_args()
+ snapshot_id = self.get_snapshot(key='id')
+ if snapshot_id:
+ args['snapshotid'] = snapshot_id
+ else:
+ args['volumeid'] = self.get_root_volume('id')
+
+ if not self.module.check_mode:
+ template = self.query_api('createTemplate', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ template = self.poll_job(template, 'template')
+
+ if template:
+ template = self.ensure_tags(resource=template, resource_type='Template')
+
+ return template
+
+ def register_template(self):
+ required_params = [
+ 'format',
+ 'url',
+ 'hypervisor',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+ template = None
+ self.result['changed'] = True
+ args = self._get_args()
+ args.update({
+ 'url': self.module.params.get('url'),
+ 'format': self.module.params.get('format'),
+ 'checksum': self.module.params.get('checksum'),
+ 'isextractable': self.module.params.get('is_extractable'),
+ 'isrouting': self.module.params.get('is_routing'),
+ 'sshkeyenabled': self.module.params.get('sshkey_enabled'),
+ 'hypervisor': self.get_hypervisor(),
+ 'domainid': self.get_domain(key='id'),
+ 'account': self.get_account(key='name'),
+ 'projectid': self.get_project(key='id'),
+ })
+
+ if not self.module.params.get('cross_zones'):
+ args['zoneid'] = self.get_zone(key='id')
+ else:
+ args['zoneid'] = -1
+
+ if not self.module.check_mode:
+ self.query_api('registerTemplate', **args)
+ template = self.get_template()
+ return template
+
+ def update_template(self, template):
+ args = {
+ 'id': template['id'],
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ 'format': self.module.params.get('format'),
+ 'isdynamicallyscalable': self.module.params.get('is_dynamically_scalable'),
+ 'isrouting': self.module.params.get('is_routing'),
+ 'ostypeid': self.get_os_type(key='id'),
+ 'passwordenabled': self.module.params.get('password_enabled'),
+ }
+ if self.has_changed(args, template):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ self.query_api('updateTemplate', **args)
+ template = self.get_template()
+
+ args = {
+ 'id': template['id'],
+ 'isextractable': self.module.params.get('is_extractable'),
+ 'isfeatured': self.module.params.get('is_featured'),
+ 'ispublic': self.module.params.get('is_public'),
+ }
+ if self.has_changed(args, template):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ self.query_api('updateTemplatePermissions', **args)
+ # Refresh
+ template = self.get_template()
+
+ if template:
+ template = self.ensure_tags(resource=template, resource_type='Template')
+
+ return template
+
+ def _is_find_option(self, param_name):
+ return param_name in self.module.params.get('template_find_options')
+
+ def _find_option_match(self, template, param_name, internal_name=None):
+ if not internal_name:
+ internal_name = param_name
+
+ if param_name in self.module.params.get('template_find_options'):
+ param_value = self.module.params.get(param_name)
+
+ if not param_value:
+ self.fail_json(msg="The param template_find_options has %s but param was not provided." % param_name)
+
+ if template[internal_name] == param_value:
+ return True
+ return False
+
+ def get_template(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'templatefilter': self.module.params.get('template_filter'),
+ 'domainid': self.get_domain(key='id'),
+ 'account': self.get_account(key='name'),
+ 'projectid': self.get_project(key='id')
+ }
+
+ cross_zones = self.module.params.get('cross_zones')
+ if not cross_zones:
+ args['zoneid'] = self.get_zone(key='id')
+
+ template_found = None
+
+ templates = self.query_api('listTemplates', **args)
+ if templates:
+ for tmpl in templates['template']:
+
+ if self._is_find_option('cross_zones') and not self._find_option_match(
+ template=tmpl,
+ param_name='cross_zones',
+ internal_name='crossZones'):
+ continue
+
+ if self._is_find_option('checksum') and not self._find_option_match(
+ template=tmpl,
+ param_name='checksum'):
+ continue
+
+ if self._is_find_option('display_text') and not self._find_option_match(
+ template=tmpl,
+ param_name='display_text',
+ internal_name='displaytext'):
+ continue
+
+ if not template_found:
+ template_found = tmpl
+ # A cross zones template has one entry per zone but the same id
+ elif tmpl['id'] == template_found['id']:
+ continue
+ else:
+ self.fail_json(msg="Multiple templates found matching provided params. Please use template_find_options.")
+
+ return template_found
+
+ def extract_template(self):
+ template = self.get_template()
+ if not template:
+ self.module.fail_json(msg="Failed: template not found")
+
+ if self.module.params.get('cross_zones'):
+ self.module.warn('cross_zones parameter is ignored when state is extracted')
+
+ args = {
+ 'id': template['id'],
+ 'url': self.module.params.get('url'),
+ 'mode': self.module.params.get('mode'),
+ 'zoneid': self.get_zone(key='id')
+ }
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ template = self.query_api('extractTemplate', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ template = self.poll_job(template, 'template')
+ return template
+
+ def remove_template(self):
+ template = self.get_template()
+ if template:
+ self.result['changed'] = True
+
+ args = {
+ 'id': template['id']
+ }
+ if not self.module.params.get('cross_zones'):
+ args['zoneid'] = self.get_zone(key='id')
+
+ if not self.module.check_mode:
+ res = self.query_api('deleteTemplate', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ res = self.poll_job(res, 'template')
+ return template
+
+ def get_result(self, template):
+ super(AnsibleCloudStackTemplate, self).get_result(template)
+ if template:
+ if 'isextractable' in template:
+ self.result['is_extractable'] = True if template['isextractable'] else False
+ if 'isfeatured' in template:
+ self.result['is_featured'] = True if template['isfeatured'] else False
+ if 'ispublic' in template:
+ self.result['is_public'] = True if template['ispublic'] else False
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ display_text=dict(),
+ url=dict(),
+ vm=dict(),
+ snapshot=dict(),
+ os_type=dict(),
+ is_public=dict(type='bool'),
+ is_featured=dict(type='bool'),
+ is_dynamically_scalable=dict(type='bool'),
+ is_extractable=dict(type='bool'),
+ is_routing=dict(type='bool'),
+ checksum=dict(),
+ template_filter=dict(default='self', choices=['all', 'featured', 'self', 'selfexecutable', 'sharedexecutable', 'executable', 'community']),
+ template_find_options=dict(
+ type='list',
+ elements='str',
+ choices=['display_text', 'checksum', 'cross_zones'],
+ aliases=['template_find_option'],
+ default=[],
+ ),
+ hypervisor=dict(),
+ requires_hvm=dict(type='bool'),
+ password_enabled=dict(type='bool', no_log=False),
+ template_tag=dict(),
+ sshkey_enabled=dict(type='bool'),
+ format=dict(choices=['QCOW2', 'RAW', 'VHD', 'OVA']),
+ details=dict(),
+ bits=dict(type='int', choices=[32, 64], default=64),
+ state=dict(choices=['present', 'absent', 'extracted'], default='present'),
+ cross_zones=dict(type='bool', default=False),
+ mode=dict(choices=['http_download', 'ftp_upload'], default='http_download'),
+ zone=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ poll_async=dict(type='bool', default=True),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ mutually_exclusive=(
+ ['url', 'vm'],
+ ['zone', 'cross_zones'],
+ ),
+ supports_check_mode=True
+ )
+
+ acs_tpl = AnsibleCloudStackTemplate(module)
+
+ state = module.params.get('state')
+ if state == 'absent':
+ tpl = acs_tpl.remove_template()
+
+ elif state == 'extracted':
+ tpl = acs_tpl.extract_template()
+ else:
+ tpl = acs_tpl.present_template()
+
+ result = acs_tpl.get_result(tpl)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_traffic_type.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_traffic_type.py
new file mode 100644
index 00000000..22ec3ec3
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_traffic_type.py
@@ -0,0 +1,321 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2019, Patryk D. Cichy <patryk.d.cichy@gmail.com>
+# 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: cs_traffic_type
+short_description: Manages traffic types on CloudStack Physical Networks
+description:
+ - Add, remove, update Traffic Types associated with CloudStack Physical Networks.
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+author:
+ - Patryk Cichy (@PatTheSilent)
+version_added: 0.1.0
+options:
+ physical_network:
+ description:
+ - the name of the Physical Network
+ required: true
+ type: str
+ zone:
+ description:
+ - Name of the zone with the physical network.
+ - Default zone will be used if this is empty.
+ type: str
+ traffic_type:
+ description:
+ - the trafficType to be added to the physical network.
+ required: true
+ choices: [Management, Guest, Public, Storage]
+ type: str
+ state:
+ description:
+ - State of the traffic type
+ choices: [present, absent]
+ default: present
+ type: str
+ hyperv_networklabel:
+ description:
+ - The network name label of the physical device dedicated to this traffic on a HyperV host.
+ type: str
+ isolation_method:
+ description:
+ - Use if the physical network has multiple isolation types and traffic type is public.
+ choices: [vlan, vxlan]
+ type: str
+ kvm_networklabel:
+ description:
+ - The network name label of the physical device dedicated to this traffic on a KVM host.
+ type: str
+ ovm3_networklabel:
+ description:
+ - The network name of the physical device dedicated to this traffic on an OVM3 host.
+ type: str
+ vlan:
+ description:
+ - The VLAN id to be used for Management traffic by VMware host.
+ type: str
+ vmware_networklabel:
+ description:
+ - The network name label of the physical device dedicated to this traffic on a VMware host.
+ type: str
+ xen_networklabel:
+ description:
+ - The network name label of the physical device dedicated to this traffic on a XenServer host.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+'''
+
+EXAMPLES = '''
+- name: add a traffic type
+ ngine_io.cloudstack.cs_traffic_type:
+ physical_network: public-network
+ traffic_type: Guest
+ zone: test-zone
+
+- name: update traffic type
+ ngine_io.cloudstack.cs_traffic_type:
+ physical_network: public-network
+ traffic_type: Guest
+ kvm_networklabel: cloudbr0
+ zone: test-zone
+
+- name: remove traffic type
+ ngine_io.cloudstack.cs_traffic_type:
+ physical_network: public-network
+ traffic_type: Public
+ state: absent
+ zone: test-zone
+'''
+
+RETURN = '''
+---
+id:
+ description: ID of the network provider
+ returned: success
+ type: str
+ sample: 659c1840-9374-440d-a412-55ca360c9d3c
+traffic_type:
+ description: the trafficType that was added to the physical network
+ returned: success
+ type: str
+ sample: Public
+hyperv_networklabel:
+ description: The network name label of the physical device dedicated to this traffic on a HyperV host
+ returned: success
+ type: str
+ sample: HyperV Internal Switch
+kvm_networklabel:
+ description: The network name label of the physical device dedicated to this traffic on a KVM host
+ returned: success
+ type: str
+ sample: cloudbr0
+ovm3_networklabel:
+ description: The network name of the physical device dedicated to this traffic on an OVM3 host
+ returned: success
+ type: str
+ sample: cloudbr0
+physical_network:
+ description: the physical network this belongs to
+ returned: success
+ type: str
+ sample: 28ed70b7-9a1f-41bf-94c3-53a9f22da8b6
+vmware_networklabel:
+ description: The network name label of the physical device dedicated to this traffic on a VMware host
+ returned: success
+ type: str
+ sample: Management Network
+xen_networklabel:
+ description: The network name label of the physical device dedicated to this traffic on a XenServer host
+ returned: success
+ type: str
+ sample: xenbr0
+zone:
+ description: Name of zone the physical network is in.
+ returned: success
+ type: str
+ sample: ch-gva-2
+'''
+
+from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together
+from ansible.module_utils.basic import AnsibleModule
+
+
+class AnsibleCloudStackTrafficType(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackTrafficType, self).__init__(module)
+ self.returns = {
+ 'traffictype': 'traffic_type',
+ 'hypervnetworklabel': 'hyperv_networklabel',
+ 'kvmnetworklabel': 'kvm_networklabel',
+ 'ovm3networklabel': 'ovm3_networklabel',
+ 'physicalnetworkid': 'physical_network',
+ 'vmwarenetworklabel': 'vmware_networklabel',
+ 'xennetworklabel': 'xen_networklabel'
+ }
+
+ self.traffic_type = None
+
+ def _get_label_args(self):
+ label_args = dict()
+ if self.module.params.get('hyperv_networklabel'):
+ label_args.update(dict(hypervnetworklabel=self.module.params.get('hyperv_networklabel')))
+ if self.module.params.get('kvm_networklabel'):
+ label_args.update(dict(kvmnetworklabel=self.module.params.get('kvm_networklabel')))
+ if self.module.params.get('ovm3_networklabel'):
+ label_args.update(dict(ovm3networklabel=self.module.params.get('ovm3_networklabel')))
+ if self.module.params.get('vmware_networklabel'):
+ label_args.update(dict(vmwarenetworklabel=self.module.params.get('vmware_networklabel')))
+ return label_args
+
+ def _get_additional_args(self):
+ additional_args = dict()
+
+ if self.module.params.get('isolation_method'):
+ additional_args.update(dict(isolationmethod=self.module.params.get('isolation_method')))
+
+ if self.module.params.get('vlan'):
+ additional_args.update(dict(vlan=self.module.params.get('vlan')))
+
+ additional_args.update(self._get_label_args())
+
+ return additional_args
+
+ def get_traffic_types(self):
+ args = {
+ 'physicalnetworkid': self.get_physical_network(key='id')
+ }
+ traffic_types = self.query_api('listTrafficTypes', **args)
+ return traffic_types
+
+ def get_traffic_type(self):
+ if self.traffic_type:
+ return self.traffic_type
+
+ traffic_type = self.module.params.get('traffic_type')
+
+ traffic_types = self.get_traffic_types()
+
+ if traffic_types:
+ for t_type in traffic_types['traffictype']:
+ if traffic_type.lower() in [t_type['traffictype'].lower(), t_type['id']]:
+ self.traffic_type = t_type
+ break
+ return self.traffic_type
+
+ def present_traffic_type(self):
+ traffic_type = self.get_traffic_type()
+ if traffic_type:
+ self.traffic_type = self.update_traffic_type()
+ else:
+ self.result['changed'] = True
+ self.traffic_type = self.add_traffic_type()
+
+ return self.traffic_type
+
+ def add_traffic_type(self):
+ traffic_type = self.module.params.get('traffic_type')
+ args = {
+ 'physicalnetworkid': self.get_physical_network(key='id'),
+ 'traffictype': traffic_type
+ }
+ args.update(self._get_additional_args())
+ if not self.module.check_mode:
+ resource = self.query_api('addTrafficType', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.traffic_type = self.poll_job(resource, 'traffictype')
+ return self.traffic_type
+
+ def absent_traffic_type(self):
+ traffic_type = self.get_traffic_type()
+ if traffic_type:
+
+ args = {
+ 'id': traffic_type['id']
+ }
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ resource = self.query_api('deleteTrafficType', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(resource, 'traffictype')
+
+ return traffic_type
+
+ def update_traffic_type(self):
+
+ traffic_type = self.get_traffic_type()
+ args = {
+ 'id': traffic_type['id']
+ }
+ args.update(self._get_label_args())
+ if self.has_changed(args, traffic_type):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ resource = self.query_api('updateTrafficType', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.traffic_type = self.poll_job(resource, 'traffictype')
+
+ return self.traffic_type
+
+
+def setup_module_object():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ physical_network=dict(required=True),
+ zone=dict(),
+ state=dict(choices=['present', 'absent'], default='present'),
+ traffic_type=dict(required=True, choices=['Management', 'Guest', 'Public', 'Storage']),
+ hyperv_networklabel=dict(),
+ isolation_method=dict(choices=['vlan', 'vxlan']),
+ kvm_networklabel=dict(),
+ ovm3_networklabel=dict(),
+ vlan=dict(),
+ vmware_networklabel=dict(),
+ xen_networklabel=dict(),
+ poll_async=dict(type='bool', default=True)
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+ return module
+
+
+def execute_module(module):
+ actt = AnsibleCloudStackTrafficType(module)
+ state = module.params.get('state')
+
+ if state in ['present']:
+ result = actt.present_traffic_type()
+ else:
+ result = actt.absent_traffic_type()
+
+ return actt.get_result(result)
+
+
+def main():
+ module = setup_module_object()
+ result = execute_module(module)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_user.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_user.py
new file mode 100644
index 00000000..816e5f70
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_user.py
@@ -0,0 +1,436 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_user
+short_description: Manages users on Apache CloudStack based clouds.
+description:
+ - Create, update, disable, lock, enable and remove users.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ username:
+ description:
+ - Username of the user.
+ type: str
+ required: true
+ account:
+ description:
+ - Account the user will be created under.
+ - Required on I(state=present).
+ type: str
+ password:
+ description:
+ - Password of the user to be created.
+ - Required on I(state=present).
+ - Only considered on creation and will not be updated if user exists.
+ type: str
+ first_name:
+ description:
+ - First name of the user.
+ - Required on I(state=present).
+ type: str
+ last_name:
+ description:
+ - Last name of the user.
+ - Required on I(state=present).
+ type: str
+ email:
+ description:
+ - Email of the user.
+ - Required on I(state=present).
+ type: str
+ timezone:
+ description:
+ - Timezone of the user.
+ type: str
+ keys_registered:
+ description:
+ - If API keys of the user should be generated.
+ - "Note: Keys can not be removed by the API again."
+ type: bool
+ default: no
+ domain:
+ description:
+ - Domain the user is related to.
+ type: str
+ default: ROOT
+ state:
+ description:
+ - State of the user.
+ - C(unlocked) is an alias for C(enabled).
+ type: str
+ default: present
+ choices: [ present, absent, enabled, disabled, locked, unlocked ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create an user in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_user:
+ account: developers
+ username: johndoe
+ password: S3Cur3
+ last_name: Doe
+ first_name: John
+ email: john.doe@example.com
+ domain: CUSTOMERS
+
+- name: Lock an existing user in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_user:
+ username: johndoe
+ domain: CUSTOMERS
+ state: locked
+
+- name: Disable an existing user in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_user:
+ username: johndoe
+ domain: CUSTOMERS
+ state: disabled
+
+- name: Enable/unlock an existing user in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_user:
+ username: johndoe
+ domain: CUSTOMERS
+ state: enabled
+
+- name: Remove an user in domain 'CUSTOMERS'
+ ngine_io.cloudstack.cs_user:
+ name: customer_xy
+ domain: CUSTOMERS
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the user.
+ returned: success
+ type: str
+ sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8
+username:
+ description: Username of the user.
+ returned: success
+ type: str
+ sample: johndoe
+fist_name:
+ description: First name of the user.
+ returned: success
+ type: str
+ sample: John
+last_name:
+ description: Last name of the user.
+ returned: success
+ type: str
+ sample: Doe
+email:
+ description: Emailof the user.
+ returned: success
+ type: str
+ sample: john.doe@example.com
+user_api_key:
+ description: API key of the user.
+ returned: success
+ type: str
+ sample: JLhcg8VWi8DoFqL2sSLZMXmGojcLnFrOBTipvBHJjySODcV4mCOo29W2duzPv5cALaZnXj5QxDx3xQfaQt3DKg
+user_api_secret:
+ description: API secret of the user.
+ returned: success
+ type: str
+ sample: FUELo3LB9fa1UopjTLPdqLv_6OXQMJZv9g9N4B_Ao3HFz8d6IGFCV9MbPFNM8mwz00wbMevja1DoUNDvI8C9-g
+account:
+ description: Account name of the user.
+ returned: success
+ type: str
+ sample: developers
+account_type:
+ description: Type of the account.
+ returned: success
+ type: str
+ sample: user
+timezone:
+ description: Timezone of the user.
+ returned: success
+ type: str
+ sample: enabled
+created:
+ description: Date the user was created.
+ returned: success
+ type: str
+ sample: Doe
+state:
+ description: State of the user.
+ returned: success
+ type: str
+ sample: enabled
+domain:
+ description: Domain the user is related.
+ returned: success
+ type: str
+ sample: ROOT
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackUser(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackUser, self).__init__(module)
+ self.returns = {
+ 'username': 'username',
+ 'firstname': 'first_name',
+ 'lastname': 'last_name',
+ 'email': 'email',
+ 'secretkey': 'user_api_secret',
+ 'apikey': 'user_api_key',
+ 'timezone': 'timezone',
+ }
+ self.account_types = {
+ 'user': 0,
+ 'root_admin': 1,
+ 'domain_admin': 2,
+ }
+ self.user = None
+
+ def get_account_type(self):
+ account_type = self.module.params.get('account_type')
+ return self.account_types[account_type]
+
+ def get_user(self):
+ if not self.user:
+ args = {
+ 'domainid': self.get_domain('id'),
+ 'fetch_list': True,
+ }
+
+ users = self.query_api('listUsers', **args)
+
+ if users:
+ user_name = self.module.params.get('username')
+ for u in users:
+ if user_name.lower() == u['username'].lower():
+ self.user = u
+ break
+ return self.user
+
+ def enable_user(self):
+ user = self.get_user()
+ if not user:
+ user = self.present_user()
+
+ if user['state'].lower() != 'enabled':
+ self.result['changed'] = True
+ args = {
+ 'id': user['id'],
+ }
+ if not self.module.check_mode:
+ res = self.query_api('enableUser', **args)
+ user = res['user']
+ return user
+
+ def lock_user(self):
+ user = self.get_user()
+ if not user:
+ user = self.present_user()
+
+ # we need to enable the user to lock it.
+ if user['state'].lower() == 'disabled':
+ user = self.enable_user()
+
+ if user['state'].lower() != 'locked':
+ self.result['changed'] = True
+
+ args = {
+ 'id': user['id'],
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('lockUser', **args)
+ user = res['user']
+
+ return user
+
+ def disable_user(self):
+ user = self.get_user()
+ if not user:
+ user = self.present_user()
+
+ if user['state'].lower() != 'disabled':
+ self.result['changed'] = True
+ args = {
+ 'id': user['id'],
+ }
+ if not self.module.check_mode:
+ user = self.query_api('disableUser', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ user = self.poll_job(user, 'user')
+ return user
+
+ def present_user(self):
+ required_params = [
+ 'account',
+ 'email',
+ 'password',
+ 'first_name',
+ 'last_name',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ user = self.get_user()
+ if user:
+ user = self._update_user(user)
+ else:
+ user = self._create_user(user)
+ return user
+
+ def _get_common_args(self):
+ return {
+ 'firstname': self.module.params.get('first_name'),
+ 'lastname': self.module.params.get('last_name'),
+ 'email': self.module.params.get('email'),
+ 'timezone': self.module.params.get('timezone'),
+ }
+
+ def _create_user(self, user):
+ self.result['changed'] = True
+
+ args = self._get_common_args()
+ args.update({
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain('id'),
+ 'username': self.module.params.get('username'),
+ 'password': self.module.params.get('password'),
+ })
+
+ if not self.module.check_mode:
+ res = self.query_api('createUser', **args)
+ user = res['user']
+
+ # register user api keys
+ if self.module.params.get('keys_registered'):
+ res = self.query_api('registerUserKeys', id=user['id'])
+ user.update(res['userkeys'])
+
+ return user
+
+ def _update_user(self, user):
+ args = self._get_common_args()
+ args.update({
+ 'id': user['id'],
+ })
+
+ if self.has_changed(args, user):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('updateUser', **args)
+
+ user = res['user']
+
+ # register user api keys
+ if 'apikey' not in user and self.module.params.get('keys_registered'):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('registerUserKeys', id=user['id'])
+ user.update(res['userkeys'])
+ return user
+
+ def absent_user(self):
+ user = self.get_user()
+ if user:
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ self.query_api('deleteUser', id=user['id'])
+
+ return user
+
+ def get_result(self, user):
+ super(AnsibleCloudStackUser, self).get_result(user)
+ if user:
+ if 'accounttype' in user:
+ for key, value in self.account_types.items():
+ if value == user['accounttype']:
+ self.result['account_type'] = key
+ break
+
+ # secretkey has been removed since CloudStack 4.10 from listUsers API
+ if self.module.params.get('keys_registered') and 'apikey' in user and 'secretkey' not in user:
+ user_keys = self.query_api('getUserKeys', id=user['id'])
+ if user_keys:
+ self.result['user_api_secret'] = user_keys['userkeys'].get('secretkey')
+
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ username=dict(required=True),
+ account=dict(),
+ state=dict(choices=['present', 'absent', 'enabled', 'disabled', 'locked', 'unlocked'], default='present'),
+ domain=dict(default='ROOT'),
+ email=dict(),
+ first_name=dict(),
+ last_name=dict(),
+ password=dict(no_log=True),
+ timezone=dict(),
+ keys_registered=dict(type='bool', default=False),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_acc = AnsibleCloudStackUser(module)
+
+ state = module.params.get('state')
+
+ if state == 'absent':
+ user = acs_acc.absent_user()
+
+ elif state in ['enabled', 'unlocked']:
+ user = acs_acc.enable_user()
+
+ elif state == 'disabled':
+ user = acs_acc.disable_user()
+
+ elif state == 'locked':
+ user = acs_acc.lock_user()
+
+ else:
+ user = acs_acc.present_user()
+
+ result = acs_acc.get_result(user)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vlan_ip_range.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vlan_ip_range.py
new file mode 100644
index 00000000..aaca4158
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vlan_ip_range.py
@@ -0,0 +1,397 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2018, David Passante <@dpassante>
+# 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: cs_vlan_ip_range
+short_description: Manages VLAN IP ranges on Apache CloudStack based clouds.
+description:
+ - Create and delete VLAN IP range.
+author: David Passante (@dpassante)
+version_added: 0.1.0
+options:
+ network:
+ description:
+ - The network name or id.
+ - Required if I(for_virtual_network) and I(physical_network) are not set.
+ type: str
+ physical_network:
+ description:
+ - The physical network name or id.
+ type: str
+ start_ip:
+ description:
+ - The beginning IPv4 address in the VLAN IP range.
+ - Only considered on create.
+ type: str
+ required: true
+ end_ip:
+ description:
+ - The ending IPv4 address in the VLAN IP range.
+ - If not specified, value of I(start_ip) is used.
+ - Only considered on create.
+ type: str
+ gateway:
+ description:
+ - The gateway of the VLAN IP range.
+ - Required if I(state=present).
+ type: str
+ netmask:
+ description:
+ - The netmask of the VLAN IP range.
+ - Required if I(state=present).
+ type: str
+ start_ipv6:
+ description:
+ - The beginning IPv6 address in the IPv6 network range.
+ - Only considered on create.
+ type: str
+ end_ipv6:
+ description:
+ - The ending IPv6 address in the IPv6 network range.
+ - If not specified, value of I(start_ipv6) is used.
+ - Only considered on create.
+ type: str
+ gateway_ipv6:
+ description:
+ - The gateway of the IPv6 network.
+ - Only considered on create.
+ type: str
+ cidr_ipv6:
+ description:
+ - The CIDR of IPv6 network, must be at least /64.
+ type: str
+ vlan:
+ description:
+ - The ID or VID of the network.
+ - If not specified, will be defaulted to the vlan of the network.
+ type: str
+ pod:
+ description:
+ - Name of the pod.
+ type: str
+ version_added: 1.0.0
+ state:
+ description:
+ - State of the network ip range.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ zone:
+ description:
+ - The Zone ID of the VLAN IP range.
+ - If not set, default zone is used.
+ type: str
+ domain:
+ description:
+ - Domain of the account owning the VLAN.
+ type: str
+ account:
+ description:
+ - Account who owns the VLAN.
+ - Mutually exclusive with I(project).
+ type: str
+ project:
+ description:
+ - Project who owns the VLAN.
+ - Mutually exclusive with I(account).
+ type: str
+ for_virtual_network:
+ description:
+ - C(yes) if VLAN is of Virtual type, C(no) if Direct.
+ - If set to C(yes) but neither I(physical_network) or I(network) is set CloudStack will try to add the
+ VLAN range to the Physical Network with a Public traffic type.
+ type: bool
+ default: no
+ version_added: 1.0.0
+ for_system_vms:
+ description:
+ - C(yes) if IP range is set to system vms, C(no) if not
+ type: bool
+ default: no
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: create a VLAN IP range for network test
+ ngine_io.cloudstack.cs_vlan_ip_range:
+ network: test
+ vlan: 98
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ zone: zone-02
+
+- name: remove a VLAN IP range for network test
+ ngine_io.cloudstack.cs_vlan_ip_range:
+ state: absent
+ network: test
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ zone: zone-02
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the VLAN IP range.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+network:
+ description: The network of vlan range
+ returned: if available
+ type: str
+ sample: test
+vlan:
+ description: The ID or VID of the VLAN.
+ returned: success
+ type: str
+ sample: vlan://98
+gateway:
+ description: IPv4 gateway.
+ returned: success
+ type: str
+ sample: 10.2.4.1
+netmask:
+ description: IPv4 netmask.
+ returned: success
+ type: str
+ sample: 255.255.255.0
+gateway_ipv6:
+ description: IPv6 gateway.
+ returned: if available
+ type: str
+ sample: 2001:db8::1
+cidr_ipv6:
+ description: The CIDR of IPv6 network.
+ returned: if available
+ type: str
+ sample: 2001:db8::/64
+zone:
+ description: Name of zone.
+ returned: success
+ type: str
+ sample: zone-02
+domain:
+ description: Domain name of the VLAN IP range.
+ returned: success
+ type: str
+ sample: ROOT
+account:
+ description: Account who owns the network.
+ returned: if available
+ type: str
+ sample: example account
+project:
+ description: Project who owns the network.
+ returned: if available
+ type: str
+ sample: example project
+for_systemvms:
+ description: Whether VLAN IP range is dedicated to system vms or not.
+ returned: success
+ type: bool
+ sample: false
+for_virtual_network:
+ description: Whether VLAN IP range is of Virtual type or not.
+ returned: success
+ type: bool
+ sample: false
+physical_network:
+ description: The physical network VLAN IP range belongs to.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+start_ip:
+ description: The start ip of the VLAN IP range.
+ returned: success
+ type: str
+ sample: 10.2.4.10
+end_ip:
+ description: The end ip of the VLAN IP range.
+ returned: success
+ type: str
+ sample: 10.2.4.100
+start_ipv6:
+ description: The start ipv6 of the VLAN IP range.
+ returned: if available
+ type: str
+ sample: 2001:db8::10
+end_ipv6:
+ description: The end ipv6 of the VLAN IP range.
+ returned: if available
+ type: str
+ sample: 2001:db8::50
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackVlanIpRange(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackVlanIpRange, self).__init__(module)
+ self.returns = {
+ 'startip': 'start_ip',
+ 'endip': 'end_ip',
+ 'physicalnetworkid': 'physical_network',
+ 'vlan': 'vlan',
+ 'forsystemvms': 'for_systemvms',
+ 'forvirtualnetwork': 'for_virtual_network',
+ 'gateway': 'gateway',
+ 'netmask': 'netmask',
+ 'ip6gateway': 'gateway_ipv6',
+ 'ip6cidr': 'cidr_ipv6',
+ 'startipv6': 'start_ipv6',
+ 'endipv6': 'end_ipv6',
+ }
+ self.ip_range = None
+
+ def get_vlan_ip_range(self):
+ if not self.ip_range:
+ args = {
+ 'zoneid': self.get_zone(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'networkid': self.get_network(key='id'),
+ }
+
+ res = self.query_api('listVlanIpRanges', **args)
+ if res:
+ ip_range_list = res['vlaniprange']
+
+ params = {
+ 'startip': self.module.params.get('start_ip'),
+ 'endip': self.get_or_fallback('end_ip', 'start_ip'),
+ }
+
+ for ipr in ip_range_list:
+ if params['startip'] == ipr['startip'] and params['endip'] == ipr['endip']:
+ self.ip_range = ipr
+ break
+
+ return self.ip_range
+
+ def present_vlan_ip_range(self):
+ ip_range = self.get_vlan_ip_range()
+
+ if not ip_range:
+ ip_range = self.create_vlan_ip_range()
+
+ return ip_range
+
+ def create_vlan_ip_range(self):
+ self.result['changed'] = True
+
+ vlan = self.module.params.get('vlan')
+
+ args = {
+ 'zoneid': self.get_zone(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'startip': self.module.params.get('start_ip'),
+ 'endip': self.get_or_fallback('end_ip', 'start_ip'),
+ 'netmask': self.module.params.get('netmask'),
+ 'gateway': self.module.params.get('gateway'),
+ 'startipv6': self.module.params.get('start_ipv6'),
+ 'endipv6': self.get_or_fallback('end_ipv6', 'start_ipv6'),
+ 'ip6gateway': self.module.params.get('gateway_ipv6'),
+ 'ip6cidr': self.module.params.get('cidr_ipv6'),
+ 'vlan': self.get_network(key='vlan') if not vlan else vlan,
+ 'networkid': self.get_network(key='id'),
+ 'forvirtualnetwork': self.module.params.get('for_virtual_network'),
+ 'forsystemvms': self.module.params.get('for_system_vms'),
+ 'podid': self.get_pod(key='id'),
+ }
+ if self.module.params.get('physical_network'):
+ args['physicalnetworkid'] = self.get_physical_network(key='id')
+
+ if not self.module.check_mode:
+ res = self.query_api('createVlanIpRange', **args)
+
+ self.ip_range = res['vlan']
+
+ return self.ip_range
+
+ def absent_vlan_ip_range(self):
+ ip_range = self.get_vlan_ip_range()
+
+ if ip_range:
+ self.result['changed'] = True
+
+ args = {
+ 'id': ip_range['id'],
+ }
+
+ if not self.module.check_mode:
+ self.query_api('deleteVlanIpRange', **args)
+
+ return ip_range
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ network=dict(type='str'),
+ physical_network=dict(type='str'),
+ zone=dict(type='str'),
+ start_ip=dict(type='str', required=True),
+ end_ip=dict(type='str'),
+ gateway=dict(type='str'),
+ netmask=dict(type='str'),
+ start_ipv6=dict(type='str'),
+ end_ipv6=dict(type='str'),
+ gateway_ipv6=dict(type='str'),
+ cidr_ipv6=dict(type='str'),
+ vlan=dict(type='str'),
+ state=dict(choices=['present', 'absent'], default='present'),
+ domain=dict(type='str'),
+ account=dict(type='str'),
+ project=dict(type='str'),
+ pod=dict(type='str'),
+ for_virtual_network=dict(type='bool', default=False),
+ for_system_vms=dict(type='bool', default=False),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ mutually_exclusive=(
+ ['account', 'project'],
+ ),
+ required_if=(("state", "present", ("gateway", "netmask")),),
+ supports_check_mode=True,
+ )
+
+ acs_vlan_ip_range = AnsibleCloudStackVlanIpRange(module)
+
+ state = module.params.get('state')
+ if state == 'absent':
+ ipr = acs_vlan_ip_range.absent_vlan_ip_range()
+
+ else:
+ ipr = acs_vlan_ip_range.present_vlan_ip_range()
+
+ result = acs_vlan_ip_range.get_result(ipr)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vmsnapshot.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vmsnapshot.py
new file mode 100644
index 00000000..83b77a70
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vmsnapshot.py
@@ -0,0 +1,278 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, 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: cs_vmsnapshot
+short_description: Manages VM snapshots on Apache CloudStack based clouds.
+description:
+ - Create, remove and revert VM from snapshots.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Unique Name of the snapshot. In CloudStack terms display name.
+ type: str
+ required: true
+ aliases: [ display_name ]
+ vm:
+ description:
+ - Name of the virtual machine.
+ type: str
+ required: true
+ description:
+ description:
+ - Description of the snapshot.
+ type: str
+ snapshot_memory:
+ description:
+ - Snapshot memory if set to true.
+ default: no
+ type: bool
+ zone:
+ description:
+ - Name of the zone in which the VM is in. If not set, default zone is used.
+ type: str
+ project:
+ description:
+ - Name of the project the VM is assigned to.
+ type: str
+ state:
+ description:
+ - State of the snapshot.
+ type: str
+ default: present
+ choices: [ present, absent, revert ]
+ domain:
+ description:
+ - Domain the VM snapshot is related to.
+ type: str
+ account:
+ description:
+ - Account the VM snapshot is related to.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "To delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a VM snapshot of disk and memory before an upgrade
+ ngine_io.cloudstack.cs_vmsnapshot:
+ name: Snapshot before upgrade
+ vm: web-01
+ snapshot_memory: yes
+
+- name: Revert a VM to a snapshot after a failed upgrade
+ ngine_io.cloudstack.cs_vmsnapshot:
+ name: Snapshot before upgrade
+ vm: web-01
+ state: revert
+
+- name: Remove a VM snapshot after successful upgrade
+ ngine_io.cloudstack.cs_vmsnapshot:
+ name: Snapshot before upgrade
+ vm: web-01
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the snapshot.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+name:
+ description: Name of the snapshot.
+ returned: success
+ type: str
+ sample: snapshot before update
+display_name:
+ description: Display name of the snapshot.
+ returned: success
+ type: str
+ sample: snapshot before update
+created:
+ description: date of the snapshot.
+ returned: success
+ type: str
+ sample: 2015-03-29T14:57:06+0200
+current:
+ description: true if the snapshot is current
+ returned: success
+ type: bool
+ sample: True
+state:
+ description: state of the vm snapshot
+ returned: success
+ type: str
+ sample: Allocated
+type:
+ description: type of vm snapshot
+ returned: success
+ type: str
+ sample: DiskAndMemory
+description:
+ description: description of vm snapshot
+ returned: success
+ type: str
+ sample: snapshot brought to you by Ansible
+domain:
+ description: Domain the vm snapshot is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the vm snapshot is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project the vm snapshot is related to.
+ returned: success
+ type: str
+ sample: Production
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackVmSnapshot(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackVmSnapshot, self).__init__(module)
+ self.returns = {
+ 'type': 'type',
+ 'current': 'current',
+ }
+
+ def get_snapshot(self):
+ args = {
+ 'virtualmachineid': self.get_vm('id'),
+ 'account': self.get_account('name'),
+ 'domainid': self.get_domain('id'),
+ 'projectid': self.get_project('id'),
+ 'name': self.module.params.get('name'),
+ }
+ snapshots = self.query_api('listVMSnapshot', **args)
+ if snapshots:
+ return snapshots['vmSnapshot'][0]
+ return None
+
+ def create_snapshot(self):
+ snapshot = self.get_snapshot()
+ if not snapshot:
+ self.result['changed'] = True
+
+ args = {
+ 'virtualmachineid': self.get_vm('id'),
+ 'name': self.module.params.get('name'),
+ 'description': self.module.params.get('description'),
+ 'snapshotmemory': self.module.params.get('snapshot_memory'),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createVMSnapshot', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ snapshot = self.poll_job(res, 'vmsnapshot')
+
+ if snapshot:
+ snapshot = self.ensure_tags(resource=snapshot, resource_type='Snapshot')
+
+ return snapshot
+
+ def remove_snapshot(self):
+ snapshot = self.get_snapshot()
+ if snapshot:
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('deleteVMSnapshot', vmsnapshotid=snapshot['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ res = self.poll_job(res, 'vmsnapshot')
+ return snapshot
+
+ def revert_vm_to_snapshot(self):
+ snapshot = self.get_snapshot()
+ if snapshot:
+ self.result['changed'] = True
+
+ if snapshot['state'] != "Ready":
+ self.module.fail_json(msg="snapshot state is '%s', not ready, could not revert VM" % snapshot['state'])
+
+ if not self.module.check_mode:
+ res = self.query_api('revertToVMSnapshot', vmsnapshotid=snapshot['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if res and poll_async:
+ res = self.poll_job(res, 'vmsnapshot')
+ return snapshot
+
+ self.module.fail_json(msg="snapshot not found, could not revert VM")
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True, aliases=['display_name']),
+ vm=dict(required=True),
+ description=dict(),
+ zone=dict(),
+ snapshot_memory=dict(type='bool', default=False),
+ state=dict(choices=['present', 'absent', 'revert'], default='present'),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ poll_async=dict(type='bool', default=True),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_vmsnapshot = AnsibleCloudStackVmSnapshot(module)
+
+ state = module.params.get('state')
+ if state in ['revert']:
+ snapshot = acs_vmsnapshot.revert_vm_to_snapshot()
+ elif state in ['absent']:
+ snapshot = acs_vmsnapshot.remove_snapshot()
+ else:
+ snapshot = acs_vmsnapshot.create_snapshot()
+
+ result = acs_vmsnapshot.get_result(snapshot)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_volume.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_volume.py
new file mode 100644
index 00000000..5947675c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_volume.py
@@ -0,0 +1,561 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2015, Jefferson Girão <jefferson@girao.net>
+# Copyright (c) 2015, 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: cs_volume
+short_description: Manages volumes on Apache CloudStack based clouds.
+description:
+ - Create, destroy, attach, detach, extract or upload volumes.
+author:
+ - Jefferson Girão (@jeffersongirao)
+ - René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the volume.
+ - I(name) can only contain ASCII letters.
+ type: str
+ required: true
+ account:
+ description:
+ - Account the volume is related to.
+ type: str
+ device_id:
+ description:
+ - ID of the device on a VM the volume is attached to.
+ - Only considered if I(state) is C(attached).
+ type: int
+ custom_id:
+ description:
+ - Custom id to the resource.
+ - Allowed to Root Admins only.
+ type: str
+ disk_offering:
+ description:
+ - Name of the disk offering to be used.
+ - Required one of I(disk_offering), I(snapshot) if volume is not already I(state=present).
+ type: str
+ display_volume:
+ description:
+ - Whether to display the volume to the end user or not.
+ - Allowed to Root Admins only.
+ type: bool
+ domain:
+ description:
+ - Name of the domain the volume to be deployed in.
+ type: str
+ max_iops:
+ description:
+ - Max iops
+ type: int
+ min_iops:
+ description:
+ - Min iops
+ type: int
+ project:
+ description:
+ - Name of the project the volume to be deployed in.
+ type: str
+ size:
+ description:
+ - Size of disk in GB
+ type: int
+ snapshot:
+ description:
+ - The snapshot name for the disk volume.
+ - Required one of I(disk_offering), I(snapshot) if volume is not already I(state=present).
+ type: str
+ force:
+ description:
+ - Force removal of volume even it is attached to a VM.
+ - Considered on I(state=absent) only.
+ default: no
+ type: bool
+ shrink_ok:
+ description:
+ - Whether to allow to shrink the volume.
+ default: no
+ type: bool
+ vm:
+ description:
+ - Name of the virtual machine to attach the volume to.
+ type: str
+ zone:
+ description:
+ - Name of the zone in which the volume should be deployed.
+ - If not set, default zone is used.
+ type: str
+ state:
+ description:
+ - State of the volume.
+ type: str
+ default: present
+ choices: [ present, absent, attached, detached, extracted, uploaded ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "To delete all tags, set a empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+ url:
+ description:
+ - URL to which the volume would be extracted on I(state=extracted)
+ - or the URL where to download the volume on I(state=uploaded).
+ - Only considered if I(state) is C(extracted) or C(uploaded).
+ type: str
+ mode:
+ description:
+ - Mode for the volume extraction.
+ - Only considered if I(state=extracted).
+ type: str
+ choices: [ http_download, ftp_upload ]
+ default: http_download
+ format:
+ description:
+ - The format for the volume.
+ - Only considered if I(state=uploaded).
+ type: str
+ choices: [ QCOW2, RAW, VHD, VHDX, OVA ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: create volume within project and zone with specified storage options
+ ngine_io.cloudstack.cs_volume:
+ name: web-vm-1-volume
+ project: Integration
+ zone: ch-zrh-ix-01
+ disk_offering: PerfPlus Storage
+ size: 20
+
+- name: create/attach volume to instance
+ ngine_io.cloudstack.cs_volume:
+ name: web-vm-1-volume
+ disk_offering: PerfPlus Storage
+ size: 20
+ vm: web-vm-1
+ state: attached
+
+- name: detach volume
+ ngine_io.cloudstack.cs_volume:
+ name: web-vm-1-volume
+ state: detached
+
+- name: remove volume
+ ngine_io.cloudstack.cs_volume:
+ name: web-vm-1-volume
+ state: absent
+
+- name: Extract DATA volume to make it downloadable
+ ngine_io.cloudstack.cs_volume:
+ state: extracted
+ name: web-vm-1-volume
+ register: data_vol_out
+
+- name: Create new volume by downloading source volume
+ ngine_io.cloudstack.cs_volume:
+ state: uploaded
+ name: web-vm-1-volume-2
+ format: VHD
+ url: "{{ data_vol_out.url }}"
+'''
+
+RETURN = '''
+id:
+ description: ID of the volume.
+ returned: success
+ type: str
+ sample:
+name:
+ description: Name of the volume.
+ returned: success
+ type: str
+ sample: web-volume-01
+display_name:
+ description: Display name of the volume.
+ returned: success
+ type: str
+ sample: web-volume-01
+group:
+ description: Group the volume belongs to
+ returned: success
+ type: str
+ sample: web
+domain:
+ description: Domain the volume belongs to
+ returned: success
+ type: str
+ sample: example domain
+project:
+ description: Project the volume belongs to
+ returned: success
+ type: str
+ sample: Production
+zone:
+ description: Name of zone the volume is in.
+ returned: success
+ type: str
+ sample: ch-gva-2
+created:
+ description: Date of the volume was created.
+ returned: success
+ type: str
+ sample: 2014-12-01T14:57:57+0100
+attached:
+ description: Date of the volume was attached.
+ returned: success
+ type: str
+ sample: 2014-12-01T14:57:57+0100
+type:
+ description: Disk volume type.
+ returned: success
+ type: str
+ sample: DATADISK
+size:
+ description: Size of disk volume.
+ returned: success
+ type: int
+ sample: 20
+vm:
+ description: Name of the vm the volume is attached to (not returned when detached)
+ returned: success
+ type: str
+ sample: web-01
+state:
+ description: State of the volume
+ returned: success
+ type: str
+ sample: Attached
+device_id:
+ description: Id of the device on user vm the volume is attached to (not returned when detached)
+ returned: success
+ type: int
+ sample: 1
+url:
+ description: The url of the uploaded volume or the download url depending extraction mode.
+ returned: success when I(state=extracted)
+ type: str
+ sample: http://1.12.3.4/userdata/387e2c7c-7c42-4ecc-b4ed-84e8367a1965.vhd
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_required_together,
+ cs_argument_spec
+)
+
+
+class AnsibleCloudStackVolume(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackVolume, self).__init__(module)
+ self.returns = {
+ 'group': 'group',
+ 'attached': 'attached',
+ 'vmname': 'vm',
+ 'deviceid': 'device_id',
+ 'type': 'type',
+ 'size': 'size',
+ 'url': 'url',
+ }
+ self.volume = None
+
+ def get_volume(self):
+ if not self.volume:
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'displayvolume': self.module.params.get('display_volume'),
+ 'type': 'DATADISK',
+ 'fetch_list': True,
+ }
+ # Do not filter on DATADISK when state=extracted
+ if self.module.params.get('state') == 'extracted':
+ del args['type']
+
+ volumes = self.query_api('listVolumes', **args)
+ if volumes:
+ volume_name = self.module.params.get('name')
+ for v in volumes:
+ if volume_name.lower() == v['name'].lower():
+ self.volume = v
+ break
+ return self.volume
+
+ def get_snapshot(self, key=None):
+ snapshot = self.module.params.get('snapshot')
+ if not snapshot:
+ return None
+
+ args = {
+ 'name': snapshot,
+ 'account': self.get_account('name'),
+ 'domainid': self.get_domain('id'),
+ 'projectid': self.get_project('id'),
+ }
+ snapshots = self.query_api('listSnapshots', **args)
+ if snapshots:
+ return self._get_by_key(key, snapshots['snapshot'][0])
+ self.module.fail_json(msg="Snapshot with name %s not found" % snapshot)
+
+ def present_volume(self):
+ volume = self.get_volume()
+ if volume:
+ volume = self.update_volume(volume)
+ else:
+ disk_offering_id = self.get_disk_offering(key='id')
+ snapshot_id = self.get_snapshot(key='id')
+
+ if not disk_offering_id and not snapshot_id:
+ self.module.fail_json(msg="Required one of: disk_offering,snapshot")
+
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'diskofferingid': disk_offering_id,
+ 'displayvolume': self.module.params.get('display_volume'),
+ 'maxiops': self.module.params.get('max_iops'),
+ 'miniops': self.module.params.get('min_iops'),
+ 'projectid': self.get_project(key='id'),
+ 'size': self.module.params.get('size'),
+ 'snapshotid': snapshot_id,
+ 'zoneid': self.get_zone(key='id')
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createVolume', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ volume = self.poll_job(res, 'volume')
+ if volume:
+ volume = self.ensure_tags(resource=volume, resource_type='Volume')
+ self.volume = volume
+
+ return volume
+
+ def attached_volume(self):
+ volume = self.present_volume()
+
+ if volume:
+ if volume.get('virtualmachineid') != self.get_vm(key='id'):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ volume = self.detached_volume()
+
+ if 'attached' not in volume:
+ self.result['changed'] = True
+
+ args = {
+ 'id': volume['id'],
+ 'virtualmachineid': self.get_vm(key='id'),
+ 'deviceid': self.module.params.get('device_id'),
+ }
+ if not self.module.check_mode:
+ res = self.query_api('attachVolume', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ volume = self.poll_job(res, 'volume')
+ return volume
+
+ def detached_volume(self):
+ volume = self.present_volume()
+
+ if volume:
+ if 'attached' not in volume:
+ return volume
+
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('detachVolume', id=volume['id'])
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ volume = self.poll_job(res, 'volume')
+ return volume
+
+ def absent_volume(self):
+ volume = self.get_volume()
+
+ if volume:
+ if 'attached' in volume and not self.module.params.get('force'):
+ self.module.fail_json(msg="Volume '%s' is attached, use force=true for detaching and removing the volume." % volume.get('name'))
+
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ volume = self.detached_volume()
+ res = self.query_api('deleteVolume', id=volume['id'])
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'volume')
+
+ return volume
+
+ def update_volume(self, volume):
+ args_resize = {
+ 'id': volume['id'],
+ 'diskofferingid': self.get_disk_offering(key='id'),
+ 'maxiops': self.module.params.get('max_iops'),
+ 'miniops': self.module.params.get('min_iops'),
+ 'size': self.module.params.get('size')
+ }
+ # change unit from bytes to giga bytes to compare with args
+ volume_copy = volume.copy()
+ volume_copy['size'] = volume_copy['size'] / (2**30)
+
+ if self.has_changed(args_resize, volume_copy):
+
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ args_resize['shrinkok'] = self.module.params.get('shrink_ok')
+ res = self.query_api('resizeVolume', **args_resize)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ volume = self.poll_job(res, 'volume')
+ self.volume = volume
+
+ return volume
+
+ def extract_volume(self):
+ volume = self.get_volume()
+ if not volume:
+ self.module.fail_json(msg="Failed: volume not found")
+
+ args = {
+ 'id': volume['id'],
+ 'url': self.module.params.get('url'),
+ 'mode': self.module.params.get('mode').upper(),
+ 'zoneid': self.get_zone(key='id')
+ }
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('extractVolume', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ volume = self.poll_job(res, 'volume')
+ self.volume = volume
+
+ return volume
+
+ def upload_volume(self):
+ volume = self.get_volume()
+ if not volume:
+ disk_offering_id = self.get_disk_offering(key='id')
+
+ self.result['changed'] = True
+
+ args = {
+ 'name': self.module.params.get('name'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'format': self.module.params.get('format'),
+ 'url': self.module.params.get('url'),
+ 'diskofferingid': disk_offering_id,
+ }
+ if not self.module.check_mode:
+ res = self.query_api('uploadVolume', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ volume = self.poll_job(res, 'volume')
+ if volume:
+ volume = self.ensure_tags(resource=volume, resource_type='Volume')
+ self.volume = volume
+
+ return volume
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ disk_offering=dict(),
+ display_volume=dict(type='bool'),
+ max_iops=dict(type='int'),
+ min_iops=dict(type='int'),
+ size=dict(type='int'),
+ snapshot=dict(),
+ vm=dict(),
+ device_id=dict(type='int'),
+ custom_id=dict(),
+ force=dict(type='bool', default=False),
+ shrink_ok=dict(type='bool', default=False),
+ state=dict(default='present', choices=[
+ 'present',
+ 'absent',
+ 'attached',
+ 'detached',
+ 'extracted',
+ 'uploaded',
+ ]),
+ zone=dict(),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ poll_async=dict(type='bool', default=True),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ url=dict(),
+ mode=dict(choices=['http_download', 'ftp_upload'], default='http_download'),
+ format=dict(choices=['QCOW2', 'RAW', 'VHD', 'VHDX', 'OVA']),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ mutually_exclusive=(
+ ['snapshot', 'disk_offering'],
+ ),
+ required_if=[
+ ('state', 'uploaded', ['url', 'format']),
+ ],
+ supports_check_mode=True
+ )
+
+ acs_vol = AnsibleCloudStackVolume(module)
+
+ state = module.params.get('state')
+
+ if state in ['absent']:
+ volume = acs_vol.absent_volume()
+ elif state in ['attached']:
+ volume = acs_vol.attached_volume()
+ elif state in ['detached']:
+ volume = acs_vol.detached_volume()
+ elif state == 'extracted':
+ volume = acs_vol.extract_volume()
+ elif state == 'uploaded':
+ volume = acs_vol.upload_volume()
+ else:
+ volume = acs_vol.present_volume()
+
+ result = acs_vol.get_result(volume)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc.py
new file mode 100644
index 00000000..45837dd2
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc.py
@@ -0,0 +1,391 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_vpc
+short_description: "Manages VPCs on Apache CloudStack based clouds."
+description:
+ - Create, update and delete VPCs.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the VPC.
+ type: str
+ required: true
+ display_text:
+ description:
+ - Display text of the VPC.
+ - If not set, I(name) will be used for creating.
+ type: str
+ cidr:
+ description:
+ - CIDR of the VPC, e.g. 10.1.0.0/16
+ - All VPC guest networks' CIDRs must be within this CIDR.
+ - Required on I(state=present).
+ type: str
+ network_domain:
+ description:
+ - Network domain for the VPC.
+ - All networks inside the VPC will belong to this domain.
+ - Only considered while creating the VPC, can not be changed.
+ type: str
+ vpc_offering:
+ description:
+ - Name of the VPC offering.
+ - If not set, default VPC offering is used.
+ type: str
+ clean_up:
+ description:
+ - Whether to redeploy a VPC router or not when I(state=restarted)
+ type: bool
+ state:
+ description:
+ - State of the VPC.
+ - The state C(present) creates a started VPC.
+ - The state C(stopped) is only considered while creating the VPC, added in version 2.6.
+ type: str
+ default: present
+ choices:
+ - present
+ - absent
+ - stopped
+ - restarted
+ domain:
+ description:
+ - Domain the VPC is related to.
+ type: str
+ account:
+ description:
+ - Account the VPC is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the VPC is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone.
+ - If not set, default zone is used.
+ type: str
+ tags:
+ description:
+ - List of tags. Tags are a list of dictionaries having keys I(key) and I(value).
+ - "For deleting all tags, set an empty list e.g. I(tags: [])."
+ type: list
+ elements: dict
+ aliases: [ tag ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Ensure a VPC is present but not started after creating
+ ngine_io.cloudstack.cs_vpc:
+ name: my_vpc
+ display_text: My example VPC
+ cidr: 10.10.0.0/16
+ state: stopped
+
+- name: Ensure a VPC is present and started after creating
+ ngine_io.cloudstack.cs_vpc:
+ name: my_vpc
+ display_text: My example VPC
+ cidr: 10.10.0.0/16
+
+- name: Ensure a VPC is absent
+ ngine_io.cloudstack.cs_vpc:
+ name: my_vpc
+ state: absent
+
+- name: Ensure a VPC is restarted with clean up
+ ngine_io.cloudstack.cs_vpc:
+ name: my_vpc
+ clean_up: yes
+ state: restarted
+'''
+
+RETURN = '''
+---
+id:
+ description: "UUID of the VPC."
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: "Name of the VPC."
+ returned: success
+ type: str
+ sample: my_vpc
+display_text:
+ description: "Display text of the VPC."
+ returned: success
+ type: str
+ sample: My example VPC
+cidr:
+ description: "CIDR of the VPC."
+ returned: success
+ type: str
+ sample: 10.10.0.0/16
+network_domain:
+ description: "Network domain of the VPC."
+ returned: success
+ type: str
+ sample: example.com
+region_level_vpc:
+ description: "Whether the VPC is region level or not."
+ returned: success
+ type: bool
+ sample: true
+restart_required:
+ description: "Whether the VPC router needs a restart or not."
+ returned: success
+ type: bool
+ sample: true
+distributed_vpc_router:
+ description: "Whether the VPC uses distributed router or not."
+ returned: success
+ type: bool
+ sample: true
+redundant_vpc_router:
+ description: "Whether the VPC has redundant routers or not."
+ returned: success
+ type: bool
+ sample: true
+domain:
+ description: "Domain the VPC is related to."
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: "Account the VPC is related to."
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: "Name of project the VPC is related to."
+ returned: success
+ type: str
+ sample: Production
+zone:
+ description: "Name of zone the VPC is in."
+ returned: success
+ type: str
+ sample: ch-gva-2
+state:
+ description: "State of the VPC."
+ returned: success
+ type: str
+ sample: Enabled
+tags:
+ description: "List of resource tags associated with the VPC."
+ returned: success
+ type: list
+ sample: '[ { "key": "foo", "value": "bar" } ]'
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackVpc(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackVpc, self).__init__(module)
+ self.returns = {
+ 'cidr': 'cidr',
+ 'networkdomain': 'network_domain',
+ 'redundantvpcrouter': 'redundant_vpc_router',
+ 'distributedvpcrouter': 'distributed_vpc_router',
+ 'regionlevelvpc': 'region_level_vpc',
+ 'restartrequired': 'restart_required',
+ }
+ self.vpc = None
+
+ def get_vpc_offering(self, key=None):
+ vpc_offering = self.module.params.get('vpc_offering')
+ args = {
+ 'state': 'Enabled',
+ }
+ if vpc_offering:
+ args['name'] = vpc_offering
+ fail_msg = "VPC offering not found or not enabled: %s" % vpc_offering
+ else:
+ args['isdefault'] = True
+ fail_msg = "No enabled default VPC offering found"
+
+ vpc_offerings = self.query_api('listVPCOfferings', **args)
+ if vpc_offerings:
+ # The API name argument filter also matches substrings, we have to
+ # iterate over the results to get an exact match
+ for vo in vpc_offerings['vpcoffering']:
+ if 'name' in args:
+ if args['name'] == vo['name']:
+ return self._get_by_key(key, vo)
+ # Return the first offering found, if not queried for the name
+ else:
+ return self._get_by_key(key, vo)
+ self.module.fail_json(msg=fail_msg)
+
+ def get_vpc(self):
+ if self.vpc:
+ return self.vpc
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'fetch_list': True,
+ }
+ vpcs = self.query_api('listVPCs', **args)
+ if vpcs:
+ vpc_name = self.module.params.get('name')
+ for v in vpcs:
+ if vpc_name in [v['name'], v['displaytext'], v['id']]:
+ # Fail if the identifier matches more than one VPC
+ if self.vpc:
+ self.module.fail_json(msg="More than one VPC found with the provided identifyer: %s" % vpc_name)
+ else:
+ self.vpc = v
+ return self.vpc
+
+ def restart_vpc(self):
+ self.result['changed'] = True
+ vpc = self.get_vpc()
+ if vpc and not self.module.check_mode:
+ args = {
+ 'id': vpc['id'],
+ 'cleanup': self.module.params.get('clean_up'),
+ }
+ res = self.query_api('restartVPC', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'vpc')
+ return vpc
+
+ def present_vpc(self):
+ vpc = self.get_vpc()
+ if not vpc:
+ vpc = self._create_vpc(vpc)
+ else:
+ vpc = self._update_vpc(vpc)
+
+ if vpc:
+ vpc = self.ensure_tags(resource=vpc, resource_type='Vpc')
+ return vpc
+
+ def _create_vpc(self, vpc):
+ self.result['changed'] = True
+ args = {
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.get_or_fallback('display_text', 'name'),
+ 'networkdomain': self.module.params.get('network_domain'),
+ 'vpcofferingid': self.get_vpc_offering(key='id'),
+ 'cidr': self.module.params.get('cidr'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'zoneid': self.get_zone(key='id'),
+ 'start': self.module.params.get('state') != 'stopped'
+ }
+ self.result['diff']['after'] = args
+ if not self.module.check_mode:
+ res = self.query_api('createVPC', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vpc = self.poll_job(res, 'vpc')
+ return vpc
+
+ def _update_vpc(self, vpc):
+ args = {
+ 'id': vpc['id'],
+ 'displaytext': self.module.params.get('display_text'),
+ }
+ if self.has_changed(args, vpc):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateVPC', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vpc = self.poll_job(res, 'vpc')
+ return vpc
+
+ def absent_vpc(self):
+ vpc = self.get_vpc()
+ if vpc:
+ self.result['changed'] = True
+ self.result['diff']['before'] = vpc
+ if not self.module.check_mode:
+ res = self.query_api('deleteVPC', id=vpc['id'])
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'vpc')
+ return vpc
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ cidr=dict(),
+ display_text=dict(),
+ vpc_offering=dict(),
+ network_domain=dict(),
+ clean_up=dict(type='bool'),
+ state=dict(choices=['present', 'absent', 'stopped', 'restarted'], default='present'),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ zone=dict(),
+ tags=dict(type='list', elements='dict', aliases=['tag']),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ required_if=[
+ ('state', 'present', ['cidr']),
+ ],
+ supports_check_mode=True,
+ )
+
+ acs_vpc = AnsibleCloudStackVpc(module)
+
+ state = module.params.get('state')
+ if state == 'absent':
+ vpc = acs_vpc.absent_vpc()
+ elif state == 'restarted':
+ vpc = acs_vpc.restart_vpc()
+ else:
+ vpc = acs_vpc.present_vpc()
+
+ result = acs_vpc.get_result(vpc)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc_offering.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc_offering.py
new file mode 100644
index 00000000..be129a1e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc_offering.py
@@ -0,0 +1,319 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, David Passante (@dpassante)
+# 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: cs_vpc_offering
+short_description: Manages vpc offerings on Apache CloudStack based clouds.
+description:
+ - Create, update, enable, disable and remove CloudStack VPC offerings.
+author: David Passante (@dpassante)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - The name of the vpc offering
+ type: str
+ required: true
+ state:
+ description:
+ - State of the vpc offering.
+ type: str
+ choices: [ enabled, present, disabled, absent ]
+ default: present
+ display_text:
+ description:
+ - Display text of the vpc offerings
+ type: str
+ service_capabilities:
+ description:
+ - Desired service capabilities as part of vpc offering.
+ type: list
+ elements: dict
+ aliases: [ service_capability ]
+ service_offering:
+ description:
+ - The name or ID of the service offering for the VPC router appliance.
+ type: str
+ supported_services:
+ description:
+ - Services supported by the vpc offering
+ type: list
+ elements: str
+ aliases: [ supported_service ]
+ service_providers:
+ description:
+ - provider to service mapping. If not specified, the provider for the service will be mapped to the default provider on the physical network
+ type: list
+ elements: dict
+ aliases: [ service_provider ]
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Create a vpc offering and enable it
+ ngine_io.cloudstack.cs_vpc_offering:
+ name: my_vpc_offering
+ display_text: vpc offering description
+ state: enabled
+ supported_services: [ Dns, Dhcp ]
+ service_providers:
+ - {service: 'dns', provider: 'VpcVirtualRouter'}
+ - {service: 'dhcp', provider: 'VpcVirtualRouter'}
+
+- name: Create a vpc offering with redundant router
+ ngine_io.cloudstack.cs_vpc_offering:
+ name: my_vpc_offering
+ display_text: vpc offering description
+ supported_services: [ Dns, Dhcp, SourceNat ]
+ service_providers:
+ - {service: 'dns', provider: 'VpcVirtualRouter'}
+ - {service: 'dhcp', provider: 'VpcVirtualRouter'}
+ - {service: 'SourceNat', provider: 'VpcVirtualRouter'}
+ service_capabilities:
+ - {service: 'SourceNat', capabilitytype: 'RedundantRouter', capabilityvalue: true}
+
+- name: Create a region level vpc offering with distributed router
+ ngine_io.cloudstack.cs_vpc_offering:
+ name: my_vpc_offering
+ display_text: vpc offering description
+ state: present
+ supported_services: [ Dns, Dhcp, SourceNat ]
+ service_providers:
+ - {service: 'dns', provider: 'VpcVirtualRouter'}
+ - {service: 'dhcp', provider: 'VpcVirtualRouter'}
+ - {service: 'SourceNat', provider: 'VpcVirtualRouter'}
+ service_capabilities:
+ - {service: 'Connectivity', capabilitytype: 'DistributedRouter', capabilityvalue: true}
+ - {service: 'Connectivity', capabilitytype: 'RegionLevelVPC', capabilityvalue: true}
+
+- name: Remove a vpc offering
+ ngine_io.cloudstack.cs_vpc_offering:
+ name: my_vpc_offering
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the vpc offering.
+ returned: success
+ type: str
+ sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f
+name:
+ description: The name of the vpc offering
+ returned: success
+ type: str
+ sample: MyCustomVPCOffering
+display_text:
+ description: The display text of the vpc offering
+ returned: success
+ type: str
+ sample: My vpc offering
+state:
+ description: The state of the vpc offering
+ returned: success
+ type: str
+ sample: Enabled
+service_offering_id:
+ description: The service offering ID.
+ returned: success
+ type: str
+ sample: c5f7a5fc-43f8-11e5-a151-feff819cdc9f
+is_default:
+ description: Whether VPC offering is the default offering or not.
+ returned: success
+ type: bool
+ sample: false
+region_level:
+ description: Indicated if the offering can support region level vpc.
+ returned: success
+ type: bool
+ sample: false
+distributed:
+ description: Indicates if the vpc offering supports distributed router for one-hop forwarding.
+ returned: success
+ type: bool
+ sample: false
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackVPCOffering(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackVPCOffering, self).__init__(module)
+ self.returns = {
+ 'serviceofferingid': 'service_offering_id',
+ 'isdefault': 'is_default',
+ 'distributedvpcrouter': 'distributed',
+ 'supportsregionLevelvpc': 'region_level',
+ }
+ self.vpc_offering = None
+
+ def get_vpc_offering(self):
+ if self.vpc_offering:
+ return self.vpc_offering
+
+ args = {
+ 'name': self.module.params.get('name'),
+ }
+ vo = self.query_api('listVPCOfferings', **args)
+
+ if vo:
+ for vpc_offer in vo['vpcoffering']:
+ if args['name'] == vpc_offer['name']:
+ self.vpc_offering = vpc_offer
+
+ return self.vpc_offering
+
+ def get_service_offering_id(self):
+ service_offering = self.module.params.get('service_offering')
+ if not service_offering:
+ return None
+
+ args = {
+ 'issystem': True
+ }
+
+ service_offerings = self.query_api('listServiceOfferings', **args)
+ if service_offerings:
+ for s in service_offerings['serviceoffering']:
+ if service_offering in [s['name'], s['id']]:
+ return s['id']
+ self.fail_json(msg="Service offering '%s' not found" % service_offering)
+
+ def create_or_update(self):
+ vpc_offering = self.get_vpc_offering()
+
+ if not vpc_offering:
+ vpc_offering = self.create_vpc_offering()
+
+ return self.update_vpc_offering(vpc_offering)
+
+ def create_vpc_offering(self):
+ vpc_offering = None
+ self.result['changed'] = True
+ args = {
+ 'name': self.module.params.get('name'),
+ 'state': self.module.params.get('state'),
+ 'displaytext': self.module.params.get('display_text'),
+ 'supportedservices': self.module.params.get('supported_services'),
+ 'serviceproviderlist': self.module.params.get('service_providers'),
+ 'serviceofferingid': self.get_service_offering_id(),
+ 'servicecapabilitylist': self.module.params.get('service_capabilities'),
+ }
+
+ required_params = [
+ 'display_text',
+ 'supported_services',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ if not self.module.check_mode:
+ res = self.query_api('createVPCOffering', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vpc_offering = self.poll_job(res, 'vpcoffering')
+
+ return vpc_offering
+
+ def delete_vpc_offering(self):
+ vpc_offering = self.get_vpc_offering()
+
+ if vpc_offering:
+ self.result['changed'] = True
+
+ args = {
+ 'id': vpc_offering['id'],
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('deleteVPCOffering', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vpc_offering = self.poll_job(res, 'vpcoffering')
+
+ return vpc_offering
+
+ def update_vpc_offering(self, vpc_offering):
+ if not vpc_offering:
+ return vpc_offering
+
+ args = {
+ 'id': vpc_offering['id'],
+ 'state': self.module.params.get('state'),
+ 'name': self.module.params.get('name'),
+ 'displaytext': self.module.params.get('display_text'),
+ }
+
+ if args['state'] in ['enabled', 'disabled']:
+ args['state'] = args['state'].title()
+ else:
+ del args['state']
+
+ if self.has_changed(args, vpc_offering):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('updateVPCOffering', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vpc_offering = self.poll_job(res, 'vpcoffering')
+
+ return vpc_offering
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ display_text=dict(),
+ state=dict(choices=['enabled', 'present', 'disabled', 'absent'], default='present'),
+ service_capabilities=dict(type='list', elements='dict', aliases=['service_capability']),
+ service_offering=dict(),
+ supported_services=dict(type='list', elements='str', aliases=['supported_service']),
+ service_providers=dict(type='list', elements='dict', aliases=['service_provider']),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_vpc_offering = AnsibleCloudStackVPCOffering(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ vpc_offering = acs_vpc_offering.delete_vpc_offering()
+ else:
+ vpc_offering = acs_vpc_offering.create_or_update()
+
+ result = acs_vpc_offering.get_result(vpc_offering)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_connection.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_connection.py
new file mode 100644
index 00000000..4f77b561
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_connection.py
@@ -0,0 +1,349 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, 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 = r'''
+---
+module: cs_vpn_connection
+short_description: Manages site-to-site VPN connections on Apache CloudStack based clouds.
+description:
+ - Create and remove VPN connections.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ vpc:
+ description:
+ - Name of the VPC the VPN connection is related to.
+ type: str
+ required: true
+ vpn_customer_gateway:
+ description:
+ - Name of the VPN customer gateway.
+ type: str
+ required: true
+ passive:
+ description:
+ - State of the VPN connection.
+ - Only considered when I(state=present).
+ default: no
+ type: bool
+ force:
+ description:
+ - Activate the VPN gateway if not already activated on I(state=present).
+ - Also see M(cs_vpn_gateway).
+ default: no
+ type: bool
+ state:
+ description:
+ - State of the VPN connection.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ zone:
+ description:
+ - Name of the zone the VPC is related to.
+ - If not set, default zone is used.
+ type: str
+ domain:
+ description:
+ - Domain the VPN connection is related to.
+ type: str
+ account:
+ description:
+ - Account the VPN connection is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the VPN connection is related to.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = r'''
+- name: Create a VPN connection with activated VPN gateway
+ ngine_io.cloudstack.cs_vpn_connection:
+ vpn_customer_gateway: my vpn connection
+ vpc: my vpc
+
+- name: Create a VPN connection and force VPN gateway activation
+ ngine_io.cloudstack.cs_vpn_connection:
+ vpn_customer_gateway: my vpn connection
+ vpc: my vpc
+ force: yes
+
+- name: Remove a vpn connection
+ ngine_io.cloudstack.cs_vpn_connection:
+ vpn_customer_gateway: my vpn connection
+ vpc: my vpc
+ state: absent
+'''
+
+RETURN = r'''
+---
+id:
+ description: UUID of the VPN connection.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+vpn_gateway_id:
+ description: UUID of the VPN gateway.
+ returned: success
+ type: str
+ sample: 04589590-ac63-93f5-4ffc-b698b8ac38b6
+domain:
+ description: Domain the VPN connection is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the VPN connection is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project the VPN connection is related to.
+ returned: success
+ type: str
+ sample: Production
+created:
+ description: Date the connection was created.
+ returned: success
+ type: str
+ sample: 2014-12-01T14:57:57+0100
+dpd:
+ description: Whether dead pear detection is enabled or not.
+ returned: success
+ type: bool
+ sample: true
+esp_lifetime:
+ description: Lifetime in seconds of phase 2 VPN connection.
+ returned: success
+ type: int
+ sample: 86400
+esp_policy:
+ description: IKE policy of the VPN connection.
+ returned: success
+ type: str
+ sample: aes256-sha1;modp1536
+force_encap:
+ description: Whether encapsulation for NAT traversal is enforced or not.
+ returned: success
+ type: bool
+ sample: true
+ike_lifetime:
+ description: Lifetime in seconds of phase 1 VPN connection.
+ returned: success
+ type: int
+ sample: 86400
+ike_policy:
+ description: ESP policy of the VPN connection.
+ returned: success
+ type: str
+ sample: aes256-sha1;modp1536
+cidrs:
+ description: List of CIDRs of the customer gateway.
+ returned: success
+ type: list
+ sample: [ 10.10.10.0/24 ]
+passive:
+ description: Whether the connection is passive or not.
+ returned: success
+ type: bool
+ sample: false
+public_ip:
+ description: IP address of the VPN gateway.
+ returned: success
+ type: str
+ sample: 10.100.212.10
+gateway:
+ description: IP address of the VPN customer gateway.
+ returned: success
+ type: str
+ sample: 10.101.214.10
+state:
+ description: State of the VPN connection.
+ returned: success
+ type: str
+ sample: Connected
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackVpnConnection(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackVpnConnection, self).__init__(module)
+ self.returns = {
+ 'dpd': 'dpd',
+ 'esplifetime': 'esp_lifetime',
+ 'esppolicy': 'esp_policy',
+ 'gateway': 'gateway',
+ 'ikepolicy': 'ike_policy',
+ 'ikelifetime': 'ike_lifetime',
+ 'publicip': 'public_ip',
+ 'passive': 'passive',
+ 's2svpngatewayid': 'vpn_gateway_id',
+ }
+ self.vpn_customer_gateway = None
+
+ def get_vpn_customer_gateway(self, key=None, identifier=None, refresh=False):
+ if not refresh and self.vpn_customer_gateway:
+ return self._get_by_key(key, self.vpn_customer_gateway)
+
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'fetch_list': True,
+ }
+
+ vpn_customer_gateway = identifier or self.module.params.get('vpn_customer_gateway')
+ vcgws = self.query_api('listVpnCustomerGateways', **args)
+ if vcgws:
+ for vcgw in vcgws:
+ if vpn_customer_gateway.lower() in [vcgw['id'], vcgw['name'].lower()]:
+ self.vpn_customer_gateway = vcgw
+ return self._get_by_key(key, self.vpn_customer_gateway)
+ self.fail_json(msg="VPN customer gateway not found: %s" % vpn_customer_gateway)
+
+ def get_vpn_gateway(self, key=None):
+ args = {
+ 'vpcid': self.get_vpc(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ }
+ vpn_gateways = self.query_api('listVpnGateways', **args)
+ if vpn_gateways:
+ return self._get_by_key(key, vpn_gateways['vpngateway'][0])
+
+ elif self.module.params.get('force'):
+ if self.module.check_mode:
+ return {}
+ res = self.query_api('createVpnGateway', **args)
+ vpn_gateway = self.poll_job(res, 'vpngateway')
+ return self._get_by_key(key, vpn_gateway)
+
+ self.fail_json(msg="VPN gateway not found and not forced to create one")
+
+ def get_vpn_connection(self):
+ args = {
+ 'vpcid': self.get_vpc(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ }
+
+ vpn_conns = self.query_api('listVpnConnections', **args)
+ if vpn_conns:
+ for vpn_conn in vpn_conns['vpnconnection']:
+ if self.get_vpn_customer_gateway(key='id') == vpn_conn['s2scustomergatewayid']:
+ return vpn_conn
+
+ def present_vpn_connection(self):
+ vpn_conn = self.get_vpn_connection()
+
+ args = {
+ 's2scustomergatewayid': self.get_vpn_customer_gateway(key='id'),
+ 's2svpngatewayid': self.get_vpn_gateway(key='id'),
+ 'passive': self.module.params.get('passive'),
+ }
+
+ if not vpn_conn:
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('createVpnConnection', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vpn_conn = self.poll_job(res, 'vpnconnection')
+
+ return vpn_conn
+
+ def absent_vpn_connection(self):
+ vpn_conn = self.get_vpn_connection()
+
+ if vpn_conn:
+ self.result['changed'] = True
+
+ args = {
+ 'id': vpn_conn['id']
+ }
+
+ if not self.module.check_mode:
+ res = self.query_api('deleteVpnConnection', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'vpnconnection')
+
+ return vpn_conn
+
+ def get_result(self, vpn_conn):
+ super(AnsibleCloudStackVpnConnection, self).get_result(vpn_conn)
+ if vpn_conn:
+ if 'cidrlist' in vpn_conn:
+ self.result['cidrs'] = vpn_conn['cidrlist'].split(',') or [vpn_conn['cidrlist']]
+ # Ensure we return a bool
+ self.result['force_encap'] = True if vpn_conn.get('forceencap') else False
+ args = {
+ 'key': 'name',
+ 'identifier': vpn_conn['s2scustomergatewayid'],
+ 'refresh': True,
+ }
+ self.result['vpn_customer_gateway'] = self.get_vpn_customer_gateway(**args)
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ vpn_customer_gateway=dict(required=True),
+ vpc=dict(required=True),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ zone=dict(),
+ passive=dict(type='bool', default=False),
+ force=dict(type='bool', default=False),
+ state=dict(choices=['present', 'absent'], default='present'),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_vpn_conn = AnsibleCloudStackVpnConnection(module)
+
+ state = module.params.get('state')
+ if state == "absent":
+ vpn_conn = acs_vpn_conn.absent_vpn_connection()
+ else:
+ vpn_conn = acs_vpn_conn.present_vpn_connection()
+
+ result = acs_vpn_conn.get_result(vpn_conn)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_customer_gateway.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_customer_gateway.py
new file mode 100644
index 00000000..915784cc
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_customer_gateway.py
@@ -0,0 +1,343 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, 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 = r'''
+---
+module: cs_vpn_customer_gateway
+short_description: Manages site-to-site VPN customer gateway configurations on Apache CloudStack based clouds.
+description:
+ - Create, update and remove VPN customer gateways.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the gateway.
+ type: str
+ required: true
+ cidrs:
+ description:
+ - List of guest CIDRs behind the gateway.
+ - Required if I(state=present).
+ type: list
+ elements: str
+ aliases: [ cidr ]
+ gateway:
+ description:
+ - Public IP address of the gateway.
+ - Required if I(state=present).
+ type: str
+ esp_policy:
+ description:
+ - ESP policy in the format e.g. C(aes256-sha1;modp1536).
+ - Required if I(state=present).
+ type: str
+ ike_policy:
+ description:
+ - IKE policy in the format e.g. C(aes256-sha1;modp1536).
+ - Required if I(state=present).
+ type: str
+ ipsec_psk:
+ description:
+ - IPsec Preshared-Key.
+ - Cannot contain newline or double quotes.
+ - Required if I(state=present).
+ type: str
+ ike_lifetime:
+ description:
+ - Lifetime in seconds of phase 1 VPN connection.
+ - Defaulted to 86400 by the API on creation if not set.
+ type: int
+ esp_lifetime:
+ description:
+ - Lifetime in seconds of phase 2 VPN connection.
+ - Defaulted to 3600 by the API on creation if not set.
+ type: int
+ dpd:
+ description:
+ - Enable Dead Peer Detection.
+ - Disabled per default by the API on creation if not set.
+ type: bool
+ force_encap:
+ description:
+ - Force encapsulation for NAT traversal.
+ - Disabled per default by the API on creation if not set.
+ type: bool
+ state:
+ description:
+ - State of the VPN customer gateway.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ domain:
+ description:
+ - Domain the VPN customer gateway is related to.
+ type: str
+ account:
+ description:
+ - Account the VPN customer gateway is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the VPN gateway is related to.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ default: yes
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = r'''
+- name: Create a vpn customer gateway
+ ngine_io.cloudstack.cs_vpn_customer_gateway:
+ name: my vpn customer gateway
+ cidrs:
+ - 192.168.123.0/24
+ - 192.168.124.0/24
+ esp_policy: aes256-sha1;modp1536
+ gateway: 10.10.1.1
+ ike_policy: aes256-sha1;modp1536
+ ipsec_psk: "S3cr3Tk3Y"
+
+- name: Remove a vpn customer gateway
+ ngine_io.cloudstack.cs_vpn_customer_gateway:
+ name: my vpn customer gateway
+ state: absent
+'''
+
+RETURN = r'''
+---
+id:
+ description: UUID of the VPN customer gateway.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+gateway:
+ description: IP address of the VPN customer gateway.
+ returned: success
+ type: str
+ sample: 10.100.212.10
+domain:
+ description: Domain the VPN customer gateway is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the VPN customer gateway is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project the VPN customer gateway is related to.
+ returned: success
+ type: str
+ sample: Production
+dpd:
+ description: Whether dead pear detection is enabled or not.
+ returned: success
+ type: bool
+ sample: true
+esp_lifetime:
+ description: Lifetime in seconds of phase 2 VPN connection.
+ returned: success
+ type: int
+ sample: 86400
+esp_policy:
+ description: IKE policy of the VPN customer gateway.
+ returned: success
+ type: str
+ sample: aes256-sha1;modp1536
+force_encap:
+ description: Whether encapsulation for NAT traversal is enforced or not.
+ returned: success
+ type: bool
+ sample: true
+ike_lifetime:
+ description: Lifetime in seconds of phase 1 VPN connection.
+ returned: success
+ type: int
+ sample: 86400
+ike_policy:
+ description: ESP policy of the VPN customer gateway.
+ returned: success
+ type: str
+ sample: aes256-sha1;modp1536
+name:
+ description: Name of this customer gateway.
+ returned: success
+ type: str
+ sample: my vpn customer gateway
+cidrs:
+ description: List of CIDRs of this customer gateway.
+ returned: success
+ type: list
+ sample: [ 10.10.10.0/24 ]
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackVpnCustomerGateway(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackVpnCustomerGateway, self).__init__(module)
+ self.returns = {
+ 'dpd': 'dpd',
+ 'esplifetime': 'esp_lifetime',
+ 'esppolicy': 'esp_policy',
+ 'gateway': 'gateway',
+ 'ikepolicy': 'ike_policy',
+ 'ikelifetime': 'ike_lifetime',
+ 'ipaddress': 'ip_address',
+ }
+
+ def _common_args(self):
+ return {
+ 'name': self.module.params.get('name'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'cidrlist': ','.join(self.module.params.get('cidrs')) if self.module.params.get('cidrs') is not None else None,
+ 'esppolicy': self.module.params.get('esp_policy'),
+ 'esplifetime': self.module.params.get('esp_lifetime'),
+ 'ikepolicy': self.module.params.get('ike_policy'),
+ 'ikelifetime': self.module.params.get('ike_lifetime'),
+ 'ipsecpsk': self.module.params.get('ipsec_psk'),
+ 'dpd': self.module.params.get('dpd'),
+ 'forceencap': self.module.params.get('force_encap'),
+ 'gateway': self.module.params.get('gateway'),
+ }
+
+ def get_vpn_customer_gateway(self):
+ args = {
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id'),
+ 'fetch_list': True,
+ }
+ vpn_customer_gateway = self.module.params.get('name')
+ vpn_customer_gateways = self.query_api('listVpnCustomerGateways', **args)
+ if vpn_customer_gateways:
+ for vgw in vpn_customer_gateways:
+ if vpn_customer_gateway.lower() in [vgw['id'], vgw['name'].lower()]:
+ return vgw
+
+ def present_vpn_customer_gateway(self):
+ vpn_customer_gateway = self.get_vpn_customer_gateway()
+ required_params = [
+ 'cidrs',
+ 'esp_policy',
+ 'gateway',
+ 'ike_policy',
+ 'ipsec_psk',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ if not vpn_customer_gateway:
+ vpn_customer_gateway = self._create_vpn_customer_gateway(vpn_customer_gateway)
+ else:
+ vpn_customer_gateway = self._update_vpn_customer_gateway(vpn_customer_gateway)
+
+ return vpn_customer_gateway
+
+ def _create_vpn_customer_gateway(self, vpn_customer_gateway):
+ self.result['changed'] = True
+ args = self._common_args()
+ if not self.module.check_mode:
+ res = self.query_api('createVpnCustomerGateway', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vpn_customer_gateway = self.poll_job(res, 'vpncustomergateway')
+ return vpn_customer_gateway
+
+ def _update_vpn_customer_gateway(self, vpn_customer_gateway):
+ args = self._common_args()
+ args.update({'id': vpn_customer_gateway['id']})
+ if self.has_changed(args, vpn_customer_gateway, skip_diff_for_keys=['ipsecpsk']):
+ self.result['changed'] = True
+ if not self.module.check_mode:
+ res = self.query_api('updateVpnCustomerGateway', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vpn_customer_gateway = self.poll_job(res, 'vpncustomergateway')
+ return vpn_customer_gateway
+
+ def absent_vpn_customer_gateway(self):
+ vpn_customer_gateway = self.get_vpn_customer_gateway()
+ if vpn_customer_gateway:
+ self.result['changed'] = True
+ args = {
+ 'id': vpn_customer_gateway['id']
+ }
+ if not self.module.check_mode:
+ res = self.query_api('deleteVpnCustomerGateway', **args)
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'vpncustomergateway')
+
+ return vpn_customer_gateway
+
+ def get_result(self, vpn_customer_gateway):
+ super(AnsibleCloudStackVpnCustomerGateway, self).get_result(vpn_customer_gateway)
+ if vpn_customer_gateway:
+ if 'cidrlist' in vpn_customer_gateway:
+ self.result['cidrs'] = vpn_customer_gateway['cidrlist'].split(',') or [vpn_customer_gateway['cidrlist']]
+ # Ensure we return a bool
+ self.result['force_encap'] = True if vpn_customer_gateway.get('forceencap') else False
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ name=dict(required=True),
+ state=dict(choices=['present', 'absent'], default='present'),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ cidrs=dict(type='list', elements='str', aliases=['cidr']),
+ esp_policy=dict(),
+ esp_lifetime=dict(type='int'),
+ gateway=dict(),
+ ike_policy=dict(),
+ ike_lifetime=dict(type='int'),
+ ipsec_psk=dict(no_log=True),
+ dpd=dict(type='bool'),
+ force_encap=dict(type='bool'),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_vpn_cgw = AnsibleCloudStackVpnCustomerGateway(module)
+
+ state = module.params.get('state')
+ if state == "absent":
+ vpn_customer_gateway = acs_vpn_cgw.absent_vpn_customer_gateway()
+ else:
+ vpn_customer_gateway = acs_vpn_cgw.present_vpn_customer_gateway()
+
+ result = acs_vpn_cgw.get_result(vpn_customer_gateway)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_gateway.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_gateway.py
new file mode 100644
index 00000000..7bc3ab0b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_gateway.py
@@ -0,0 +1,204 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017, 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: cs_vpn_gateway
+short_description: Manages site-to-site VPN gateways on Apache CloudStack based clouds.
+description:
+ - Creates and removes VPN site-to-site gateways.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ vpc:
+ description:
+ - Name of the VPC.
+ type: str
+ required: true
+ state:
+ description:
+ - State of the VPN gateway.
+ type: str
+ default: present
+ choices: [ present, absent ]
+ domain:
+ description:
+ - Domain the VPN gateway is related to.
+ type: str
+ account:
+ description:
+ - Account the VPN gateway is related to.
+ type: str
+ project:
+ description:
+ - Name of the project the VPN gateway is related to.
+ type: str
+ zone:
+ description:
+ - Name of the zone the VPC is related to.
+ - If not set, default zone is used.
+ type: str
+ poll_async:
+ description:
+ - Poll async jobs until job has finished.
+ type: bool
+ default: yes
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Ensure a vpn gateway is present
+ ngine_io.cloudstack.cs_vpn_gateway:
+ vpc: my VPC
+
+- name: Ensure a vpn gateway is absent
+ ngine_io.cloudstack.cs_vpn_gateway:
+ vpc: my VPC
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the VPN site-to-site gateway.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+public_ip:
+ description: IP address of the VPN site-to-site gateway.
+ returned: success
+ type: str
+ sample: 10.100.212.10
+vpc:
+ description: Name of the VPC.
+ returned: success
+ type: str
+ sample: My VPC
+domain:
+ description: Domain the VPN site-to-site gateway is related to.
+ returned: success
+ type: str
+ sample: example domain
+account:
+ description: Account the VPN site-to-site gateway is related to.
+ returned: success
+ type: str
+ sample: example account
+project:
+ description: Name of project the VPN site-to-site gateway is related to.
+ returned: success
+ type: str
+ sample: Production
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together
+)
+
+
+class AnsibleCloudStackVpnGateway(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackVpnGateway, self).__init__(module)
+ self.returns = {
+ 'publicip': 'public_ip'
+ }
+
+ def get_vpn_gateway(self):
+ args = {
+ 'vpcid': self.get_vpc(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id')
+ }
+ vpn_gateways = self.query_api('listVpnGateways', **args)
+ if vpn_gateways:
+ return vpn_gateways['vpngateway'][0]
+ return None
+
+ def present_vpn_gateway(self):
+ vpn_gateway = self.get_vpn_gateway()
+ if not vpn_gateway:
+ self.result['changed'] = True
+ args = {
+ 'vpcid': self.get_vpc(key='id'),
+ 'account': self.get_account(key='name'),
+ 'domainid': self.get_domain(key='id'),
+ 'projectid': self.get_project(key='id')
+ }
+ if not self.module.check_mode:
+ res = self.query_api('createVpnGateway', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ vpn_gateway = self.poll_job(res, 'vpngateway')
+
+ return vpn_gateway
+
+ def absent_vpn_gateway(self):
+ vpn_gateway = self.get_vpn_gateway()
+ if vpn_gateway:
+ self.result['changed'] = True
+ args = {
+ 'id': vpn_gateway['id']
+ }
+ if not self.module.check_mode:
+ res = self.query_api('deleteVpnGateway', **args)
+
+ poll_async = self.module.params.get('poll_async')
+ if poll_async:
+ self.poll_job(res, 'vpngateway')
+
+ return vpn_gateway
+
+ def get_result(self, vpn_gateway):
+ super(AnsibleCloudStackVpnGateway, self).get_result(vpn_gateway)
+ if vpn_gateway:
+ self.result['vpc'] = self.get_vpc(key='name')
+ return self.result
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ vpc=dict(required=True),
+ state=dict(choices=['present', 'absent'], default='present'),
+ domain=dict(),
+ account=dict(),
+ project=dict(),
+ zone=dict(),
+ poll_async=dict(type='bool', default=True),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_vpn_gw = AnsibleCloudStackVpnGateway(module)
+
+ state = module.params.get('state')
+ if state == "absent":
+ vpn_gateway = acs_vpn_gw.absent_vpn_gateway()
+ else:
+ vpn_gateway = acs_vpn_gw.present_vpn_gateway()
+
+ result = acs_vpn_gw.get_result(vpn_gateway)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone.py
new file mode 100644
index 00000000..51348086
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone.py
@@ -0,0 +1,377 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_zone
+short_description: Manages zones on Apache CloudStack based clouds.
+description:
+ - Create, update and remove zones.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ name:
+ description:
+ - Name of the zone.
+ type: str
+ required: true
+ id:
+ description:
+ - uuid of the existing zone.
+ type: str
+ state:
+ description:
+ - State of the zone.
+ type: str
+ default: present
+ choices: [ present, enabled, disabled, absent ]
+ domain:
+ description:
+ - Domain the zone is related to.
+ - Zone is a public zone if not set.
+ type: str
+ network_domain:
+ description:
+ - Network domain for the zone.
+ type: str
+ network_type:
+ description:
+ - Network type of the zone.
+ type: str
+ default: Basic
+ choices: [ Basic, Advanced ]
+ dns1:
+ description:
+ - First DNS for the zone.
+ - Required if I(state=present)
+ type: str
+ dns2:
+ description:
+ - Second DNS for the zone.
+ type: str
+ internal_dns1:
+ description:
+ - First internal DNS for the zone.
+ - If not set I(dns1) will be used on I(state=present).
+ type: str
+ internal_dns2:
+ description:
+ - Second internal DNS for the zone.
+ type: str
+ dns1_ipv6:
+ description:
+ - First DNS for IPv6 for the zone.
+ type: str
+ dns2_ipv6:
+ description:
+ - Second DNS for IPv6 for the zone.
+ type: str
+ guest_cidr_address:
+ description:
+ - Guest CIDR address for the zone.
+ type: str
+ dhcp_provider:
+ description:
+ - DHCP provider for the Zone.
+ type: str
+ local_storage_enabled:
+ description:
+ - Whether to enable local storage for the zone or not..
+ type: bool
+ securitygroups_enabled:
+ description:
+ - Whether the zone is security group enabled or not.
+ type: bool
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Ensure a zone is present
+ ngine_io.cloudstack.cs_zone:
+ name: ch-zrh-ix-01
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ network_type: basic
+
+- name: Ensure a zone is disabled
+ ngine_io.cloudstack.cs_zone:
+ name: ch-zrh-ix-01
+ state: disabled
+
+- name: Ensure a zone is enabled
+ ngine_io.cloudstack.cs_zone:
+ name: ch-zrh-ix-01
+ state: enabled
+
+- name: Ensure a zone is absent
+ ngine_io.cloudstack.cs_zone:
+ name: ch-zrh-ix-01
+ state: absent
+'''
+
+RETURN = '''
+---
+id:
+ description: UUID of the zone.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+name:
+ description: Name of the zone.
+ returned: success
+ type: str
+ sample: zone01
+dns1:
+ description: First DNS for the zone.
+ returned: success
+ type: str
+ sample: 8.8.8.8
+dns2:
+ description: Second DNS for the zone.
+ returned: success
+ type: str
+ sample: 8.8.4.4
+internal_dns1:
+ description: First internal DNS for the zone.
+ returned: success
+ type: str
+ sample: 8.8.8.8
+internal_dns2:
+ description: Second internal DNS for the zone.
+ returned: success
+ type: str
+ sample: 8.8.4.4
+dns1_ipv6:
+ description: First IPv6 DNS for the zone.
+ returned: success
+ type: str
+ sample: "2001:4860:4860::8888"
+dns2_ipv6:
+ description: Second IPv6 DNS for the zone.
+ returned: success
+ type: str
+ sample: "2001:4860:4860::8844"
+allocation_state:
+ description: State of the zone.
+ returned: success
+ type: str
+ sample: Enabled
+domain:
+ description: Domain the zone is related to.
+ returned: success
+ type: str
+ sample: ROOT
+network_domain:
+ description: Network domain for the zone.
+ returned: success
+ type: str
+ sample: example.com
+network_type:
+ description: Network type for the zone.
+ returned: success
+ type: str
+ sample: basic
+local_storage_enabled:
+ description: Local storage offering enabled.
+ returned: success
+ type: bool
+ sample: false
+securitygroups_enabled:
+ description: Security groups support is enabled.
+ returned: success
+ type: bool
+ sample: false
+guest_cidr_address:
+ description: Guest CIDR address for the zone
+ returned: success
+ type: str
+ sample: 10.1.1.0/24
+dhcp_provider:
+ description: DHCP provider for the zone
+ returned: success
+ type: str
+ sample: VirtualRouter
+zone_token:
+ description: Zone token
+ returned: success
+ type: str
+ sample: ccb0a60c-79c8-3230-ab8b-8bdbe8c45bb7
+tags:
+ description: List of resource tags associated with the zone.
+ returned: success
+ type: list
+ sample: [ { "key": "foo", "value": "bar" } ]
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+ cs_required_together,
+)
+
+
+class AnsibleCloudStackZone(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackZone, self).__init__(module)
+ self.returns = {
+ 'dns1': 'dns1',
+ 'dns2': 'dns2',
+ 'internaldns1': 'internal_dns1',
+ 'internaldns2': 'internal_dns2',
+ 'ipv6dns1': 'dns1_ipv6',
+ 'ipv6dns2': 'dns2_ipv6',
+ 'domain': 'network_domain',
+ 'networktype': 'network_type',
+ 'securitygroupsenabled': 'securitygroups_enabled',
+ 'localstorageenabled': 'local_storage_enabled',
+ 'guestcidraddress': 'guest_cidr_address',
+ 'dhcpprovider': 'dhcp_provider',
+ 'allocationstate': 'allocation_state',
+ 'zonetoken': 'zone_token',
+ }
+ self.zone = None
+
+ def _get_common_zone_args(self):
+ args = {
+ 'name': self.module.params.get('name'),
+ 'dns1': self.module.params.get('dns1'),
+ 'dns2': self.module.params.get('dns2'),
+ 'internaldns1': self.get_or_fallback('internal_dns1', 'dns1'),
+ 'internaldns2': self.get_or_fallback('internal_dns2', 'dns2'),
+ 'ipv6dns1': self.module.params.get('dns1_ipv6'),
+ 'ipv6dns2': self.module.params.get('dns2_ipv6'),
+ 'networktype': self.module.params.get('network_type'),
+ 'domain': self.module.params.get('network_domain'),
+ 'localstorageenabled': self.module.params.get('local_storage_enabled'),
+ 'guestcidraddress': self.module.params.get('guest_cidr_address'),
+ 'dhcpprovider': self.module.params.get('dhcp_provider'),
+ }
+ state = self.module.params.get('state')
+ if state in ['enabled', 'disabled']:
+ args['allocationstate'] = state.capitalize()
+ return args
+
+ def get_zone(self):
+ if not self.zone:
+ args = {}
+
+ uuid = self.module.params.get('id')
+ if uuid:
+ args['id'] = uuid
+ zones = self.query_api('listZones', **args)
+ if zones:
+ self.zone = zones['zone'][0]
+ return self.zone
+
+ args['name'] = self.module.params.get('name')
+ zones = self.query_api('listZones', **args)
+ if zones:
+ self.zone = zones['zone'][0]
+ return self.zone
+
+ def present_zone(self):
+ zone = self.get_zone()
+ if zone:
+ zone = self._update_zone()
+ else:
+ zone = self._create_zone()
+ return zone
+
+ def _create_zone(self):
+ required_params = [
+ 'dns1',
+ ]
+ self.module.fail_on_missing_params(required_params=required_params)
+
+ self.result['changed'] = True
+
+ args = self._get_common_zone_args()
+ args['domainid'] = self.get_domain(key='id')
+ args['securitygroupenabled'] = self.module.params.get('securitygroups_enabled')
+
+ zone = None
+ if not self.module.check_mode:
+ res = self.query_api('createZone', **args)
+ zone = res['zone']
+ return zone
+
+ def _update_zone(self):
+ zone = self.get_zone()
+
+ args = self._get_common_zone_args()
+ args['id'] = zone['id']
+
+ if self.has_changed(args, zone):
+ self.result['changed'] = True
+
+ if not self.module.check_mode:
+ res = self.query_api('updateZone', **args)
+ zone = res['zone']
+ return zone
+
+ def absent_zone(self):
+ zone = self.get_zone()
+ if zone:
+ self.result['changed'] = True
+
+ args = {
+ 'id': zone['id']
+ }
+ if not self.module.check_mode:
+ self.query_api('deleteZone', **args)
+
+ return zone
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ id=dict(),
+ name=dict(required=True),
+ dns1=dict(),
+ dns2=dict(),
+ internal_dns1=dict(),
+ internal_dns2=dict(),
+ dns1_ipv6=dict(),
+ dns2_ipv6=dict(),
+ network_type=dict(default='Basic', choices=['Basic', 'Advanced']),
+ network_domain=dict(),
+ guest_cidr_address=dict(),
+ dhcp_provider=dict(),
+ local_storage_enabled=dict(type='bool'),
+ securitygroups_enabled=dict(type='bool'),
+ state=dict(choices=['present', 'enabled', 'disabled', 'absent'], default='present'),
+ domain=dict(),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_together=cs_required_together(),
+ supports_check_mode=True
+ )
+
+ acs_zone = AnsibleCloudStackZone(module)
+
+ state = module.params.get('state')
+ if state in ['absent']:
+ zone = acs_zone.absent_zone()
+ else:
+ zone = acs_zone.present_zone()
+
+ result = acs_zone.get_result(zone)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone_info.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone_info.py
new file mode 100644
index 00000000..1581cdbf
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone_info.py
@@ -0,0 +1,207 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016, 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: cs_zone_info
+short_description: Gathering information about zones from Apache CloudStack based clouds.
+description:
+ - Gathering information from the API of a zone.
+author: René Moser (@resmo)
+version_added: 0.1.0
+options:
+ zone:
+ description:
+ - Name of the zone.
+ - If not specified, all zones are returned
+ type: str
+ aliases: [ name ]
+extends_documentation_fragment:
+- ngine_io.cloudstack.cloudstack
+'''
+
+EXAMPLES = '''
+- name: Gather information from a zone
+ ngine_io.cloudstack.cs_zone_info:
+ zone: ch-gva-1
+ register: zone
+
+- name: Show the returned results of the registered variable
+ debug:
+ msg: "{{ zone }}"
+
+- name: Gather information from all zones
+ ngine_io.cloudstack.cs_zone_info:
+ register: zones
+
+- name: Show information on all zones
+ debug:
+ msg: "{{ zones }}"
+'''
+
+RETURN = '''
+---
+zones:
+ description: A list of matching zones.
+ type: list
+ returned: success
+ contains:
+ id:
+ description: UUID of the zone.
+ returned: success
+ type: str
+ sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6
+ name:
+ description: Name of the zone.
+ returned: success
+ type: str
+ sample: zone01
+ dns1:
+ description: First DNS for the zone.
+ returned: success
+ type: str
+ sample: 8.8.8.8
+ dns2:
+ description: Second DNS for the zone.
+ returned: success
+ type: str
+ sample: 8.8.4.4
+ internal_dns1:
+ description: First internal DNS for the zone.
+ returned: success
+ type: str
+ sample: 8.8.8.8
+ internal_dns2:
+ description: Second internal DNS for the zone.
+ returned: success
+ type: str
+ sample: 8.8.4.4
+ dns1_ipv6:
+ description: First IPv6 DNS for the zone.
+ returned: success
+ type: str
+ sample: "2001:4860:4860::8888"
+ dns2_ipv6:
+ description: Second IPv6 DNS for the zone.
+ returned: success
+ type: str
+ sample: "2001:4860:4860::8844"
+ allocation_state:
+ description: State of the zone.
+ returned: success
+ type: str
+ sample: Enabled
+ domain:
+ description: Domain the zone is related to.
+ returned: success
+ type: str
+ sample: ROOT
+ network_domain:
+ description: Network domain for the zone.
+ returned: success
+ type: str
+ sample: example.com
+ network_type:
+ description: Network type for the zone.
+ returned: success
+ type: str
+ sample: basic
+ local_storage_enabled:
+ description: Local storage offering enabled.
+ returned: success
+ type: bool
+ sample: false
+ securitygroups_enabled:
+ description: Security groups support is enabled.
+ returned: success
+ type: bool
+ sample: false
+ guest_cidr_address:
+ description: Guest CIDR address for the zone
+ returned: success
+ type: str
+ sample: 10.1.1.0/24
+ dhcp_provider:
+ description: DHCP provider for the zone
+ returned: success
+ type: str
+ sample: VirtualRouter
+ zone_token:
+ description: Zone token
+ returned: success
+ type: str
+ sample: ccb0a60c-79c8-3230-ab8b-8bdbe8c45bb7
+ tags:
+ description: List of resource tags associated with the zone.
+ returned: success
+ type: list
+ sample: [ { "key": "foo", "value": "bar" } ]
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ..module_utils.cloudstack import (
+ AnsibleCloudStack,
+ cs_argument_spec,
+)
+
+
+class AnsibleCloudStackZoneInfo(AnsibleCloudStack):
+
+ def __init__(self, module):
+ super(AnsibleCloudStackZoneInfo, self).__init__(module)
+ self.returns = {
+ 'dns1': 'dns1',
+ 'dns2': 'dns2',
+ 'internaldns1': 'internal_dns1',
+ 'internaldns2': 'internal_dns2',
+ 'ipv6dns1': 'dns1_ipv6',
+ 'ipv6dns2': 'dns2_ipv6',
+ 'domain': 'network_domain',
+ 'networktype': 'network_type',
+ 'securitygroupsenabled': 'securitygroups_enabled',
+ 'localstorageenabled': 'local_storage_enabled',
+ 'guestcidraddress': 'guest_cidr_address',
+ 'dhcpprovider': 'dhcp_provider',
+ 'allocationstate': 'allocation_state',
+ 'zonetoken': 'zone_token',
+ }
+
+ def get_zone(self):
+ if self.module.params['zone']:
+ zones = [super(AnsibleCloudStackZoneInfo, self).get_zone()]
+ else:
+ zones = self.query_api('listZones')
+ if zones:
+ zones = zones['zone']
+ else:
+ zones = []
+ return {
+ 'zones': [self.update_result(resource) for resource in zones]
+ }
+
+
+def main():
+ argument_spec = cs_argument_spec()
+ argument_spec.update(dict(
+ zone=dict(type='str', aliases=['name']),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ acs_zone_info = AnsibleCloudStackZoneInfo(module=module)
+ result = acs_zone_info.get_zone()
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/requirements.txt b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/requirements.txt
new file mode 100644
index 00000000..231d91a9
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/requirements.txt
@@ -0,0 +1 @@
+cs>=0.9.0
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.ini b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.ini
new file mode 100644
index 00000000..43777b59
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.ini
@@ -0,0 +1,5 @@
+[cloudstack]
+#endpoint = https://api.exoscale.ch/compute
+endpoint = https://cloud.example.com/client/api
+key = cloudstack api key
+secret = cloudstack api secret
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.py
new file mode 100755
index 00000000..db0322cf
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.py
@@ -0,0 +1,277 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# (c) 2015, René Moser <mail@renemoser.net>
+#
+# This file is part of Ansible,
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+######################################################################
+
+"""
+Ansible CloudStack external inventory script.
+=============================================
+
+Generates Ansible inventory from CloudStack. Configuration is read from
+'cloudstack.ini'. If you need to pass the project, write a simple wrapper
+script, e.g. project_cloudstack.sh:
+
+ #!/bin/bash
+ cloudstack.py --project <your_project> $@
+
+
+When run against a specific host, this script returns the following attributes
+based on the data obtained from CloudStack API:
+
+ "web01": {
+ "cpu_number": 2,
+ "nic": [
+ {
+ "ip": "10.102.76.98",
+ "mac": "02:00:50:99:00:01",
+ "type": "Isolated",
+ "netmask": "255.255.255.0",
+ "gateway": "10.102.76.1"
+ },
+ {
+ "ip": "10.102.138.63",
+ "mac": "06:b7:5a:00:14:84",
+ "type": "Shared",
+ "netmask": "255.255.255.0",
+ "gateway": "10.102.138.1"
+ }
+ ],
+ "default_ip": "10.102.76.98",
+ "zone": "ZUERICH",
+ "created": "2014-07-02T07:53:50+0200",
+ "hypervisor": "VMware",
+ "memory": 2048,
+ "state": "Running",
+ "tags": [],
+ "cpu_speed": 1800,
+ "affinity_group": [],
+ "service_offering": "Small",
+ "cpu_used": "62%"
+ }
+
+
+usage: cloudstack.py [--list] [--host HOST] [--project PROJECT] [--domain DOMAIN]
+"""
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import sys
+import argparse
+import json
+
+try:
+ from cs import CloudStack, CloudStackException, read_config
+except ImportError:
+ print("Error: CloudStack library must be installed: pip install cs.",
+ file=sys.stderr)
+ sys.exit(1)
+
+
+class CloudStackInventory(object):
+ def __init__(self):
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--host')
+ parser.add_argument('--list', action='store_true')
+ parser.add_argument('--tag', help="Filter machines by a tag. Should be in the form key=value.")
+ parser.add_argument('--project')
+ parser.add_argument('--domain')
+
+ options = parser.parse_args()
+ try:
+ self.cs = CloudStack(**read_config())
+ except CloudStackException:
+ print("Error: Could not connect to CloudStack API", file=sys.stderr)
+
+ domain_id = None
+ if options.domain:
+ domain_id = self.get_domain_id(options.domain)
+
+ project_id = None
+ if options.project:
+ project_id = self.get_project_id(options.project, domain_id)
+
+ if options.host:
+ data = self.get_host(options.host, project_id, domain_id)
+ print(json.dumps(data, indent=2))
+
+ elif options.list:
+ tags = dict()
+ if options.tag:
+ tags['tags[0].key'], tags['tags[0].value'] = options.tag.split('=')
+ data = self.get_list(project_id, domain_id, **tags)
+ print(json.dumps(data, indent=2))
+ else:
+ print("usage: --list [--tag <tag>] | --host <hostname> [--project <project>] [--domain <domain_path>]",
+ file=sys.stderr)
+ sys.exit(1)
+
+ def get_domain_id(self, domain):
+ domains = self.cs.listDomains(listall=True)
+ if domains:
+ for d in domains['domain']:
+ if d['path'].lower() == domain.lower():
+ return d['id']
+ print("Error: Domain %s not found." % domain, file=sys.stderr)
+ sys.exit(1)
+
+ def get_project_id(self, project, domain_id=None):
+ projects = self.cs.listProjects(domainid=domain_id)
+ if projects:
+ for p in projects['project']:
+ if p['name'] == project or p['id'] == project:
+ return p['id']
+ print("Error: Project %s not found." % project, file=sys.stderr)
+ sys.exit(1)
+
+ def get_host(self, name, project_id=None, domain_id=None, **kwargs):
+ hosts = self.cs.listVirtualMachines(projectid=project_id, domainid=domain_id, fetch_list=True, **kwargs)
+ data = {}
+ if not hosts:
+ return data
+ for host in hosts:
+ host_name = host['displayname']
+ if name == host_name:
+ data['zone'] = host['zonename']
+ if 'group' in host:
+ data['group'] = host['group']
+ data['state'] = host['state']
+ data['service_offering'] = host['serviceofferingname']
+ data['affinity_group'] = host['affinitygroup']
+ data['security_group'] = host['securitygroup']
+ data['cpu_number'] = host['cpunumber']
+ if 'cpu_speed' in host:
+ data['cpu_speed'] = host['cpuspeed']
+ if 'cpuused' in host:
+ data['cpu_used'] = host['cpuused']
+ data['memory'] = host['memory']
+ data['tags'] = host['tags']
+ if 'hypervisor' in host:
+ data['hypervisor'] = host['hypervisor']
+ data['created'] = host['created']
+ data['nic'] = []
+ for nic in host['nic']:
+ nicdata = {
+ 'ip': nic['ipaddress'],
+ 'mac': nic['macaddress'],
+ 'netmask': nic['netmask'],
+ 'gateway': nic['gateway'],
+ 'type': nic['type'],
+ }
+ if 'ip6address' in nic:
+ nicdata['ip6'] = nic['ip6address']
+ if 'gateway' in nic:
+ nicdata['gateway'] = nic['gateway']
+ if 'netmask' in nic:
+ nicdata['netmask'] = nic['netmask']
+ data['nic'].append(nicdata)
+ if nic['isdefault']:
+ data['default_ip'] = nic['ipaddress']
+ if 'ip6address' in nic:
+ data['default_ip6'] = nic['ip6address']
+ break
+ return data
+
+ def get_list(self, project_id=None, domain_id=None, **kwargs):
+ data = {
+ 'all': {
+ 'hosts': [],
+ },
+ '_meta': {
+ 'hostvars': {},
+ },
+ }
+
+ groups = self.cs.listInstanceGroups(projectid=project_id, domainid=domain_id)
+ if groups:
+ for group in groups['instancegroup']:
+ group_name = group['name']
+ if group_name and group_name not in data:
+ data[group_name] = {
+ 'hosts': []
+ }
+
+ hosts = self.cs.listVirtualMachines(projectid=project_id, domainid=domain_id, fetch_list=True, **kwargs)
+ if not hosts:
+ return data
+ for host in hosts:
+ host_name = host['displayname']
+ data['all']['hosts'].append(host_name)
+ data['_meta']['hostvars'][host_name] = {}
+
+ # Make a group per zone
+ data['_meta']['hostvars'][host_name]['zone'] = host['zonename']
+ group_name = host['zonename']
+ if group_name not in data:
+ data[group_name] = {
+ 'hosts': []
+ }
+ data[group_name]['hosts'].append(host_name)
+
+ if 'group' in host:
+ data['_meta']['hostvars'][host_name]['group'] = host['group']
+ data['_meta']['hostvars'][host_name]['state'] = host['state']
+ data['_meta']['hostvars'][host_name]['service_offering'] = host['serviceofferingname']
+ data['_meta']['hostvars'][host_name]['affinity_group'] = host['affinitygroup']
+ data['_meta']['hostvars'][host_name]['security_group'] = host['securitygroup']
+ data['_meta']['hostvars'][host_name]['cpu_number'] = host['cpunumber']
+ if 'cpuspeed' in host:
+ data['_meta']['hostvars'][host_name]['cpu_speed'] = host['cpuspeed']
+ if 'cpuused' in host:
+ data['_meta']['hostvars'][host_name]['cpu_used'] = host['cpuused']
+ data['_meta']['hostvars'][host_name]['created'] = host['created']
+ data['_meta']['hostvars'][host_name]['memory'] = host['memory']
+ data['_meta']['hostvars'][host_name]['tags'] = host['tags']
+ if 'hypervisor' in host:
+ data['_meta']['hostvars'][host_name]['hypervisor'] = host['hypervisor']
+ data['_meta']['hostvars'][host_name]['created'] = host['created']
+ data['_meta']['hostvars'][host_name]['nic'] = []
+ for nic in host['nic']:
+ nicdata = {
+ 'ip': nic['ipaddress'],
+ 'mac': nic['macaddress'],
+ 'netmask': nic['netmask'],
+ 'gateway': nic['gateway'],
+ 'type': nic['type'],
+ }
+ if 'ip6address' in nic:
+ nicdata['ip6'] = nic['ip6address']
+ if 'gateway' in nic:
+ nicdata['gateway'] = nic['gateway']
+ if 'netmask' in nic:
+ nicdata['netmask'] = nic['netmask']
+ data['_meta']['hostvars'][host_name]['nic'].append(nicdata)
+ if nic['isdefault']:
+ data['_meta']['hostvars'][host_name]['default_ip'] = nic['ipaddress']
+ if 'ip6address' in nic:
+ data['_meta']['hostvars'][host_name]['default_ip6'] = nic['ip6address']
+
+ group_name = ''
+ if 'group' in host:
+ group_name = host['group']
+
+ if group_name and group_name in data:
+ data[group_name]['hosts'].append(host_name)
+ return data
+
+
+if __name__ == '__main__':
+ CloudStackInventory()
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/tasks/main.yml
new file mode 100644
index 00000000..5bbe54be
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/tasks/main.yml
@@ -0,0 +1,416 @@
+---
+- name: setup
+ cs_account:
+ name: "{{ cs_resource_prefix }}_username"
+ state: absent
+ register: acc
+
+- name: test fail if missing name
+ action: cs_account
+ register: acc
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - acc is failed
+ - 'acc.msg == "missing required arguments: name"'
+
+- name: test fail if missing params if state=present
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ register: acc
+ ignore_errors: true
+- name: verify results of fail if missing params if state=present
+ assert:
+ that:
+ - acc is failed
+ - 'acc.msg == "missing required arguments: email, username, password, first_name, last_name"'
+
+- name: test create user account in check mode
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ username: "{{ cs_resource_prefix }}_username"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ network_domain: "example.com"
+ register: acc
+ check_mode: true
+- name: verify results of create account in check mode
+ assert:
+ that:
+ - acc is changed
+
+- name: test create user account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ username: "{{ cs_resource_prefix }}_username"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ network_domain: "example.com"
+ register: acc
+- name: verify results of create account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
+
+- name: test create user account idempotence
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ username: "{{ cs_resource_prefix }}_username"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ network_domain: "example.com"
+ register: acc
+- name: verify results of create account idempotence
+ assert:
+ that:
+ - acc is not changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
+
+- name: test lock user account in check mode
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: acc
+ check_mode: true
+- name: verify results of lock user account in check mode
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
+
+- name: test lock user account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: acc
+- name: verify results of lock user account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "locked"
+ - acc.domain == "ROOT"
+
+- name: test lock user account idempotence
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: acc
+- name: verify results of lock user account idempotence
+ assert:
+ that:
+ - acc is not changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "locked"
+ - acc.domain == "ROOT"
+
+- name: test disable user account in check mode
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: disabled
+ register: acc
+ check_mode: true
+- name: verify results of disable user account in check mode
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "locked"
+ - acc.domain == "ROOT"
+
+- name: test disable user account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: disabled
+ register: acc
+- name: verify results of disable user account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "disabled"
+ - acc.domain == "ROOT"
+
+- name: test disable user account idempotence
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: disabled
+ register: acc
+- name: verify results of disable user account idempotence
+ assert:
+ that:
+ - acc is not changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "disabled"
+ - acc.domain == "ROOT"
+
+- name: test lock disabled user account in check mode
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: acc
+ check_mode: true
+- name: verify results of lock disabled user account in check mode
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "disabled"
+ - acc.domain == "ROOT"
+
+- name: test lock disabled user account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: acc
+- name: verify results of lock disabled user account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "locked"
+ - acc.domain == "ROOT"
+
+- name: test lock disabled user account idempotence
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: acc
+- name: verify results of lock disabled user account idempotence
+ assert:
+ that:
+ - acc is not changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "locked"
+ - acc.domain == "ROOT"
+
+- name: test enable user account in check mode
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: enabled
+ register: acc
+ check_mode: true
+- name: verify results of enable user account in check mode
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "locked"
+ - acc.domain == "ROOT"
+
+- name: test enable user account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: enabled
+ register: acc
+- name: verify results of enable user account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
+
+- name: test enable user account idempotence
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: enabled
+ register: acc
+- name: verify results of enable user account idempotence
+ assert:
+ that:
+ - acc is not changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
+
+- name: test remove user account in check mode
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: acc
+ check_mode: true
+- name: verify results of remove user account in check mode
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
+
+- name: test remove user account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: acc
+- name: verify results of remove user account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
+
+- name: test remove user account idempotence
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: acc
+- name: verify results of remove user account idempotence
+ assert:
+ that:
+ - acc is not changed
+
+- name: test create user disabled account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ username: "{{ cs_resource_prefix }}_username"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ network_domain: "example.com"
+ state: disabled
+ register: acc
+- name: verify results of create disabled account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "disabled"
+ - acc.domain == "ROOT"
+
+- name: test remove disabled user account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: acc
+- name: verify results of remove disabled user account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "disabled"
+ - acc.domain == "ROOT"
+
+- name: test create user locked account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ username: "{{ cs_resource_prefix }}_username"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ network_domain: "example.com"
+ state: locked
+ register: acc
+- name: verify results of create locked account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "locked"
+ - acc.domain == "ROOT"
+
+- name: test remove locked user account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: acc
+- name: verify results of remove locked user account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "locked"
+ - acc.domain == "ROOT"
+
+- name: test create user unlocked/enabled account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ username: "{{ cs_resource_prefix }}_username"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ network_domain: "example.com"
+ state: unlocked
+ register: acc
+- name: verify results of create unlocked/enabled account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
+
+- name: test remove unlocked/enabled user account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: acc
+- name: verify results of remove unlocked/enabled user account
+ assert:
+ that:
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_user"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/tasks/main.yml
new file mode 100644
index 00000000..994f21a1
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/tasks/main.yml
@@ -0,0 +1,93 @@
+---
+- name: setup
+ cs_affinitygroup:
+ name: "{{ cs_resource_prefix }}_ag"
+ state: absent
+ register: ag
+- name: verify setup
+ assert:
+ that:
+ - ag is successful
+
+- name: test fail if missing name
+ cs_affinitygroup:
+ register: ag
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - ag is failed
+ - "ag.msg == 'missing required arguments: name'"
+
+- name: test fail unknown affinity type
+ cs_affinitygroup:
+ name: "{{ cs_resource_prefix }}_ag"
+ affinity_type: unexistent affinity type
+ register: ag
+ ignore_errors: true
+- name: verify test fail unknown affinity type
+ assert:
+ that:
+ - ag is failed
+ - "ag.msg == 'affinity group type not found: unexistent affinity type'"
+
+- name: test present affinity group in check mode
+ cs_affinitygroup: name={{ cs_resource_prefix }}_ag
+ register: ag
+ check_mode: true
+- name: verify results of create affinity group in check mode
+ assert:
+ that:
+ - ag is successful
+ - ag is changed
+
+- name: test present affinity group
+ cs_affinitygroup: name={{ cs_resource_prefix }}_ag
+ register: ag
+- name: verify results of create affinity group
+ assert:
+ that:
+ - ag is successful
+ - ag is changed
+ - ag.name == "{{ cs_resource_prefix }}_ag"
+
+- name: test present affinity group is idempotence
+ cs_affinitygroup: name={{ cs_resource_prefix }}_ag
+ register: ag
+- name: verify results present affinity group is idempotence
+ assert:
+ that:
+ - ag is successful
+ - ag is not changed
+ - ag.name == "{{ cs_resource_prefix }}_ag"
+
+- name: test absent affinity group in check mode
+ cs_affinitygroup: name={{ cs_resource_prefix }}_ag state=absent
+ register: ag
+ check_mode: true
+- name: verify results of absent affinity group in check mode
+ assert:
+ that:
+ - ag is successful
+ - ag is changed
+ - ag.name == "{{ cs_resource_prefix }}_ag"
+
+- name: test absent affinity group
+ cs_affinitygroup: name={{ cs_resource_prefix }}_ag state=absent
+ register: ag
+- name: verify results of absent affinity group
+ assert:
+ that:
+ - ag is successful
+ - ag is changed
+ - ag.name == "{{ cs_resource_prefix }}_ag"
+
+- name: test absent affinity group is idempotence
+ cs_affinitygroup: name={{ cs_resource_prefix }}_ag state=absent
+ register: ag
+- name: verify results of absent affinity group is idempotence
+ assert:
+ that:
+ - ag is successful
+ - ag is not changed
+ - ag.name is undefined
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/tasks/main.yml
new file mode 100644
index 00000000..f911a7be
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/tasks/main.yml
@@ -0,0 +1,317 @@
+---
+- name: setup cluster is absent
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: cluster
+- name: verify setup cluster is absent
+ assert:
+ that:
+ - cluster is successful
+
+- name: setup zone is present
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ network_type: Basic
+ register: zone
+- name: verify setup zone is present
+ assert:
+ that:
+ - zone is successful
+
+- name: setup pod is present
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ start_ip: 10.100.10.101
+ gateway: 10.100.10.1
+ netmask: 255.255.255.0
+ register: pod
+- name: verify setup pod is present
+ assert:
+ that:
+ - pod is successful
+
+- name: test fail if missing name
+ cs_cluster:
+ zone: "{{ cs_resource_prefix }}-zone"
+ register: cluster
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - cluster is failed
+ - "cluster.msg == 'missing required arguments: name'"
+
+- name: test fail if pod not found
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ hypervisor: Simulator
+ cluster_type: CloudManaged
+ pod: unexistent
+ register: cluster
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - cluster is failed
+ - "cluster.msg == 'Pod unexistent not found in zone {{ cs_resource_prefix }}-zone'"
+
+- name: test create cluster in check mode
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ pod: "{{ cs_resource_prefix }}-pod"
+ hypervisor: Simulator
+ cluster_type: CloudManaged
+ register: cluster_origin
+ check_mode: true
+ tags: disable
+- name: verify test create cluster in check mode
+ assert:
+ that:
+ - cluster_origin is changed
+
+- name: test create cluster
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ pod: "{{ cs_resource_prefix }}-pod"
+ hypervisor: Simulator
+ cluster_type: CloudManaged
+ register: cluster_origin
+ tags: disable
+- name: verify test create cluster
+ assert:
+ that:
+ - cluster_origin is changed
+ - cluster_origin.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster_origin.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster_origin.allocation_state == "Enabled"
+ - cluster_origin.hypervisor == "Simulator"
+ - cluster_origin.cluster_type == "CloudManaged"
+
+- name: test create cluster idempotence
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-Cluster"
+ zone: "{{ cs_resource_prefix }}-Zone"
+ pod: "{{ cs_resource_prefix }}-pod"
+ hypervisor: Simulator
+ cluster_type: CloudManaged
+ register: cluster
+- name: verify test create cluster idempotence
+ assert:
+ that:
+ - cluster.id == cluster_origin.id
+ - cluster is not changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Enabled"
+ - cluster_origin.hypervisor == "Simulator"
+ - cluster.cluster_type == "CloudManaged"
+
+- name: test update cluster in check mode
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ hypervisor: Simulator
+ cluster_type: ExternalManaged
+ register: cluster
+ check_mode: true
+- name: verify test update cluster in check mode
+ assert:
+ that:
+ - cluster is changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Enabled"
+ - cluster.hypervisor == "Simulator"
+ - cluster.cluster_type == "CloudManaged"
+ - cluster.id == cluster_origin.id
+
+- name: test update cluster
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ hypervisor: Simulator
+ cluster_type: ExternalManaged
+ register: cluster
+- name: verify test update cluster
+ assert:
+ that:
+ - cluster is changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Enabled"
+ - cluster.hypervisor == "Simulator"
+ - cluster.cluster_type == "ExternalManaged"
+ - cluster.id == cluster_origin.id
+
+- name: test update cluster idempotence
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ hypervisor: Simulator
+ cluster_type: ExternalManaged
+ register: cluster
+- name: verify test update cluster idempotence
+ assert:
+ that:
+ - cluster is not changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Enabled"
+ - cluster.hypervisor == "Simulator"
+ - cluster.cluster_type == "ExternalManaged"
+ - cluster.id == cluster_origin.id
+
+- name: test disable cluster in check mode
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: disabled
+ register: cluster
+ check_mode: true
+- name: verify test disable cluster in check mode
+ assert:
+ that:
+ - cluster is changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Enabled"
+ - cluster.hypervisor == "Simulator"
+ - cluster.cluster_type == "ExternalManaged"
+ - cluster.id == cluster_origin.id
+
+- name: test disable cluster
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: disabled
+ register: cluster
+- name: verify test disable cluster
+ assert:
+ that:
+ - cluster is changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Disabled"
+ - cluster.hypervisor == "Simulator"
+ - cluster.cluster_type == "ExternalManaged"
+ - cluster.id == cluster_origin.id
+
+- name: test disable cluster idempotence
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: disabled
+ register: cluster
+- name: verify test disable cluster idempotence
+ assert:
+ that:
+ - cluster is not changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Disabled"
+ - cluster.hypervisor == "Simulator"
+ - cluster.cluster_type == "ExternalManaged"
+
+- name: test enable cluster in check mode
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: enabled
+ register: cluster
+ check_mode: true
+- name: verify test enable cluster in check mode
+ assert:
+ that:
+ - cluster is changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Disabled"
+ - cluster.hypervisor == "Simulator"
+ - cluster.cluster_type == "ExternalManaged"
+ - cluster.id == cluster_origin.id
+
+- name: test enable cluster
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: enabled
+ register: cluster
+- name: verify test enable cluster
+ assert:
+ that:
+ - cluster is changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Enabled"
+ - cluster.hypervisor == "Simulator"
+ - cluster.cluster_type == "ExternalManaged"
+ - cluster.id == cluster_origin.id
+
+- name: test enable cluster idempotence
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: enabled
+ register: cluster
+- name: verify test enable cluster idempotence
+ assert:
+ that:
+ - cluster is not changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Enabled"
+ - cluster.hypervisor == "Simulator"
+ - cluster.cluster_type == "ExternalManaged"
+ - cluster.id == cluster_origin.id
+
+- name: test remove cluster in check mode
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: cluster
+ check_mode: true
+- name: verify test remove cluster in check mode
+ assert:
+ that:
+ - cluster.id == cluster_origin.id
+ - cluster is changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Enabled"
+ - cluster_origin.hypervisor == "Simulator"
+
+- name: test remove cluster
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: cluster
+- name: verify test remove cluster
+ assert:
+ that:
+ - cluster.id == cluster_origin.id
+ - cluster is changed
+ - cluster.name == "{{ cs_resource_prefix }}-cluster"
+ - cluster.zone == "{{ cs_resource_prefix }}-zone"
+ - cluster.allocation_state == "Enabled"
+ - cluster_origin.hypervisor == "Simulator"
+
+- name: test remove cluster idempotence
+ cs_cluster:
+ name: "{{ cs_resource_prefix }}-cluster"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: cluster
+- name: verify test remove cluster idempotence
+ assert:
+ that:
+ - cluster is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/aliases
new file mode 100644
index 00000000..136c05e0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/aliases
@@ -0,0 +1 @@
+hidden
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/defaults/main.yml
new file mode 100644
index 00000000..942316bd
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+cs_resource_prefix: "cs-{{ (ansible_date_time.iso8601_micro | to_uuid).split('-')[0] }}"
+cs_common_template: CentOS 5.6 (64-bit) no GUI (Simulator)
+cs_common_service_offering: Small Instance
+cs_common_zone_adv: Sandbox-simulator-advanced
+cs_common_zone_basic: Sandbox-simulator-basic
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/tasks/main.yml
new file mode 100644
index 00000000..1b206a07
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/tasks/main.yml
@@ -0,0 +1,23 @@
+---
+- name: wait for system template available
+ cs_template:
+ name: "{{ cs_common_template }}"
+ state: absent
+ cross_zones: yes
+ template_filter: all
+ register: template
+ check_mode: true
+ until: template is changed
+ retries: 20
+ delay: 5
+
+- name: smoke test instance
+ cs_instance:
+ name: smoke-test-vm
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ register: instance
+ until: instance is successful
+ retries: 20
+ delay: 5
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/defaults/main.yml
new file mode 100644
index 00000000..3cf304ca
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+test_cs_configuration_storage: PS0-adv
+test_cs_configuration_cluster: C0-basic
+test_cs_configuration_account: admin
+test_cs_configuration_zone: Sandbox-simulator-basic
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/account.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/account.yml
new file mode 100644
index 00000000..8b20918f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/account.yml
@@ -0,0 +1,76 @@
+---
+- name: test configuration account
+ cs_configuration:
+ name: allow.public.user.templates
+ account: "{{ test_cs_configuration_account }}"
+ value: true
+ register: config
+- name: verify test configuration storage
+ assert:
+ that:
+ - config is successful
+
+- name: test update configuration account in check mode
+ cs_configuration:
+ name: allow.public.user.templates
+ account: "{{ test_cs_configuration_account }}"
+ value: false
+ register: config
+ check_mode: true
+- name: verify update configuration account in check mode
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "true"
+ - config.name == "allow.public.user.templates"
+ - config.scope == "account"
+ - config.account == "{{ test_cs_configuration_account }}"
+
+- name: test update configuration account
+ cs_configuration:
+ name: allow.public.user.templates
+ account: "{{ test_cs_configuration_account }}"
+ value: false
+ register: config
+- name: verify update configuration account
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "false"
+ - config.name == "allow.public.user.templates"
+ - config.scope == "account"
+ - config.account == "{{ test_cs_configuration_account }}"
+
+- name: test update configuration account idempotence
+ cs_configuration:
+ name: allow.public.user.templates
+ account: "{{ test_cs_configuration_account }}"
+ value: false
+ register: config
+- name: verify update configuration account idempotence
+ assert:
+ that:
+ - config is successful
+ - config is not changed
+ - config.value == "false"
+ - config.name == "allow.public.user.templates"
+ - config.scope == "account"
+ - config.account == "{{ test_cs_configuration_account }}"
+
+- name: test reset configuration account
+ cs_configuration:
+ name: allow.public.user.templates
+ account: "{{ test_cs_configuration_account }}"
+ value: true
+ register: config
+- name: verify update configuration account
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "true"
+ - config.name == "allow.public.user.templates"
+ - config.scope == "account"
+ - config.account == "{{ test_cs_configuration_account }}"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/cluster.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/cluster.yml
new file mode 100644
index 00000000..b8cb2b94
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/cluster.yml
@@ -0,0 +1,76 @@
+---
+- name: test configuration cluster
+ cs_configuration:
+ name: cpu.overprovisioning.factor
+ cluster: "{{ test_cs_configuration_cluster }}"
+ value: 1.0
+ register: config
+- name: verify test configuration cluster
+ assert:
+ that:
+ - config is successful
+
+- name: test update configuration cluster in check mode
+ cs_configuration:
+ name: cpu.overprovisioning.factor
+ cluster: "{{ test_cs_configuration_cluster }}"
+ value: 2.0
+ register: config
+ check_mode: true
+- name: verify update configuration cluster in check mode
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "1.0"
+ - config.name == "cpu.overprovisioning.factor"
+ - config.scope == "cluster"
+ - config.cluster == "{{ test_cs_configuration_cluster }}"
+
+- name: test update configuration cluster
+ cs_configuration:
+ name: cpu.overprovisioning.factor
+ cluster: "{{ test_cs_configuration_cluster }}"
+ value: 2.0
+ register: config
+- name: verify update configuration cluster
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "2.0"
+ - config.name == "cpu.overprovisioning.factor"
+ - config.scope == "cluster"
+ - config.cluster == "{{ test_cs_configuration_cluster }}"
+
+- name: test update configuration cluster idempotence
+ cs_configuration:
+ name: cpu.overprovisioning.factor
+ cluster: "{{ test_cs_configuration_cluster }}"
+ value: 2.0
+ register: config
+- name: verify update configuration cluster idempotence
+ assert:
+ that:
+ - config is successful
+ - config is not changed
+ - config.value == "2.0"
+ - config.name == "cpu.overprovisioning.factor"
+ - config.scope == "cluster"
+ - config.cluster == "{{ test_cs_configuration_cluster }}"
+
+- name: test reset configuration cluster
+ cs_configuration:
+ name: cpu.overprovisioning.factor
+ cluster: "{{ test_cs_configuration_cluster }}"
+ value: 1.0
+ register: config
+- name: verify reset configuration cluster
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "1.0"
+ - config.name == "cpu.overprovisioning.factor"
+ - config.scope == "cluster"
+ - config.cluster == "{{ test_cs_configuration_cluster }}"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/main.yml
new file mode 100644
index 00000000..e80c85f9
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/main.yml
@@ -0,0 +1,204 @@
+---
+- name: test fail if missing name
+ cs_configuration:
+ register: config
+ ignore_errors: true
+- name: verify results of fail if missing arguments
+ assert:
+ that:
+ - config is failed
+ - "config.msg.startswith('missing required arguments: ')"
+
+- name: test configuration
+ cs_configuration:
+ name: network.loadbalancer.haproxy.stats.visibility
+ value: global
+ register: config
+- name: verify test configuration
+ assert:
+ that:
+ - config is successful
+
+- name: test update configuration string in check mode
+ cs_configuration:
+ name: network.loadbalancer.haproxy.stats.visibility
+ value: all
+ register: config
+ check_mode: true
+- name: verify test update configuration string in check mode
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "global"
+ - config.name == "network.loadbalancer.haproxy.stats.visibility"
+
+- name: test update configuration string
+ cs_configuration:
+ name: network.loadbalancer.haproxy.stats.visibility
+ value: all
+ register: config
+- name: verify test update configuration string
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "all"
+ - config.name == "network.loadbalancer.haproxy.stats.visibility"
+
+- name: test update configuration string idempotence
+ cs_configuration:
+ name: network.loadbalancer.haproxy.stats.visibility
+ value: all
+ register: config
+- name: verify test update configuration string idempotence
+ assert:
+ that:
+ - config is successful
+ - config is not changed
+ - config.value == "all"
+ - config.name == "network.loadbalancer.haproxy.stats.visibility"
+
+- name: test reset configuration string
+ cs_configuration:
+ name: network.loadbalancer.haproxy.stats.visibility
+ value: global
+ register: config
+- name: verify test reset configuration string
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "global"
+ - config.name == "network.loadbalancer.haproxy.stats.visibility"
+
+- name: test configuration
+ cs_configuration:
+ name: vmware.recycle.hung.wokervm
+ value: false
+ register: config
+- name: verify test configuration
+ assert:
+ that:
+ - config is successful
+
+- name: test update configuration bool in check mode
+ cs_configuration:
+ name: vmware.recycle.hung.wokervm
+ value: true
+ register: config
+ check_mode: true
+- name: verify test update configuration bool in check mode
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "false"
+ - config.name == "vmware.recycle.hung.wokervm"
+
+- name: test update configuration bool
+ cs_configuration:
+ name: vmware.recycle.hung.wokervm
+ value: true
+ register: config
+- name: verify test update configuration bool
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "true"
+ - config.name == "vmware.recycle.hung.wokervm"
+
+- name: test update configuration bool idempotence
+ cs_configuration:
+ name: vmware.recycle.hung.wokervm
+ value: true
+ register: config
+- name: verify test update configuration bool idempotence
+ assert:
+ that:
+ - config is successful
+ - config is not changed
+ - config.value == "true"
+ - config.name == "vmware.recycle.hung.wokervm"
+
+- name: test reset configuration bool
+ cs_configuration:
+ name: vmware.recycle.hung.wokervm
+ value: false
+ register: config
+- name: verify test reset configuration bool
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "false"
+ - config.name == "vmware.recycle.hung.wokervm"
+
+- name: test configuration
+ cs_configuration:
+ name: agent.load.threshold
+ value: 0.7
+ register: config
+- name: verify test configuration
+ assert:
+ that:
+ - config is successful
+
+- name: test update configuration float in check mode
+ cs_configuration:
+ name: agent.load.threshold
+ value: 0.81
+ register: config
+ check_mode: true
+- name: verify update configuration float in check mode
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "0.7"
+ - config.name == "agent.load.threshold"
+
+- name: test update configuration float
+ cs_configuration:
+ name: agent.load.threshold
+ value: 0.81
+ register: config
+- name: verify update configuration float
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "0.81"
+ - config.name == "agent.load.threshold"
+
+- name: test update configuration float idempotence
+ cs_configuration:
+ name: agent.load.threshold
+ value: 0.81
+ register: config
+- name: verify update configuration float idempotence
+ assert:
+ that:
+ - config is successful
+ - config is not changed
+ - config.value == "0.81"
+ - config.name == "agent.load.threshold"
+
+- name: reset configuration float
+ cs_configuration:
+ name: agent.load.threshold
+ value: 0.7
+ register: config
+- name: verify reset configuration float
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "0.7"
+ - config.name == "agent.load.threshold"
+
+- include: storage.yml
+- include: account.yml
+- include: zone.yml
+- include: cluster.yml
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/storage.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/storage.yml
new file mode 100644
index 00000000..e376dcf1
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/storage.yml
@@ -0,0 +1,76 @@
+---
+- name: test configuration storage
+ cs_configuration:
+ name: storage.overprovisioning.factor
+ storage: "{{ test_cs_configuration_storage }}"
+ value: 2.0
+ register: config
+- name: verify test configuration storage
+ assert:
+ that:
+ - config is successful
+
+- name: test update configuration storage in check mode
+ cs_configuration:
+ name: storage.overprovisioning.factor
+ storage: "{{ test_cs_configuration_storage }}"
+ value: 3.0
+ register: config
+ check_mode: true
+- name: verify update configuration storage in check mode
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "2.0"
+ - config.name == "storage.overprovisioning.factor"
+ - config.scope == "storagepool"
+ - config.storage == "{{ test_cs_configuration_storage }}"
+
+- name: test update configuration storage
+ cs_configuration:
+ name: storage.overprovisioning.factor
+ storage: "{{ test_cs_configuration_storage }}"
+ value: 3.0
+ register: config
+- name: verify update configuration storage
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "3.0"
+ - config.name == "storage.overprovisioning.factor"
+ - config.scope == "storagepool"
+ - config.storage == "{{ test_cs_configuration_storage }}"
+
+- name: test update configuration storage idempotence
+ cs_configuration:
+ name: storage.overprovisioning.factor
+ storage: "{{ test_cs_configuration_storage }}"
+ value: 3.0
+ register: config
+- name: verify update configuration storage idempotence
+ assert:
+ that:
+ - config is successful
+ - config is not changed
+ - config.value == "3.0"
+ - config.name == "storage.overprovisioning.factor"
+ - config.scope == "storagepool"
+ - config.storage == "{{ test_cs_configuration_storage }}"
+
+- name: test reset configuration storage
+ cs_configuration:
+ name: storage.overprovisioning.factor
+ storage: "{{ test_cs_configuration_storage }}"
+ value: 2.0
+ register: config
+- name: verify reset configuration storage
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "2.0"
+ - config.name == "storage.overprovisioning.factor"
+ - config.scope == "storagepool"
+ - config.storage == "{{ test_cs_configuration_storage }}"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/zone.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/zone.yml
new file mode 100644
index 00000000..cd9333fa
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/zone.yml
@@ -0,0 +1,59 @@
+---
+- name: test configuration zone
+ cs_configuration:
+ name: use.external.dns
+ zone: "{{ test_cs_configuration_zone }}"
+ value: false
+ register: config
+- name: verify test configuration zone
+ assert:
+ that:
+ - config is successful
+
+- name: test update configuration zone
+ cs_configuration:
+ name: use.external.dns
+ zone: "{{ test_cs_configuration_zone }}"
+ value: true
+ register: config
+- name: verify update configuration zone
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "true"
+ - config.name == "use.external.dns"
+ - config.scope == "zone"
+ - config.zone == "{{ test_cs_configuration_zone }}"
+
+- name: test update configuration zone idempotence
+ cs_configuration:
+ name: use.external.dns
+ zone: "{{ test_cs_configuration_zone }}"
+ value: true
+ register: config
+- name: verify update configuration zone idempotence
+ assert:
+ that:
+ - config is successful
+ - config is not changed
+ - config.value == "true"
+ - config.name == "use.external.dns"
+ - config.scope == "zone"
+ - config.zone == "{{ test_cs_configuration_zone }}"
+
+- name: test reset configuration zone
+ cs_configuration:
+ name: use.external.dns
+ zone: "{{ test_cs_configuration_zone }}"
+ value: false
+ register: config
+- name: verify reset configuration zone
+ assert:
+ that:
+ - config is successful
+ - config is changed
+ - config.value == "false"
+ - config.name == "use.external.dns"
+ - config.scope == "zone"
+ - config.zone == "{{ test_cs_configuration_zone }}"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/tasks/main.yml
new file mode 100644
index 00000000..fd55788c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/tasks/main.yml
@@ -0,0 +1,143 @@
+---
+- name: setup disk offering
+ cs_disk_offering:
+ name: Small
+ state: absent
+ register: do
+- name: verify setup disk offering
+ assert:
+ that:
+ - do is successful
+
+- name: create disk offering in check mode
+ cs_disk_offering:
+ name: Small
+ disk_size: 10
+ storage_tags:
+ - eco
+ - backup
+ storage_type: local
+ register: do
+ check_mode: true
+- name: verify create disk offering in check mode
+ assert:
+ that:
+ - do is changed
+
+- name: create disk offering
+ cs_disk_offering:
+ name: Small
+ disk_size: 10
+ storage_tags:
+ - eco
+ - backup
+ storage_type: local
+ register: do
+- name: verify create disk offering
+ assert:
+ that:
+ - do is changed
+ - do.name == "Small"
+ - do.storage_tags == ['eco', 'backup']
+ - do.storage_type == "local"
+
+- name: create disk offering idempotence
+ cs_disk_offering:
+ name: Small
+ disk_size: 10
+ storage_tags:
+ - eco
+ - backup
+ storage_type: local
+ register: do
+- name: verify create disk offering idempotence
+ assert:
+ that:
+ - do is not changed
+ - do.name == "Small"
+ - do.storage_tags == ['eco', 'backup']
+ - do.storage_type == "local"
+
+- name: update disk offering in check mode
+ cs_disk_offering:
+ name: Small
+ disk_size: 10
+ display_text: Small 10GB
+ register: do
+ check_mode: true
+- name: verify create update offering in check mode
+ assert:
+ that:
+ - do is changed
+ - do.name == "Small"
+ - do.storage_tags == ['eco', 'backup']
+ - do.storage_type == "local"
+
+- name: update disk offering
+ cs_disk_offering:
+ name: Small
+ disk_size: 10
+ display_text: Small 10GB
+ register: do
+- name: verify update disk offerin
+ assert:
+ that:
+ - do is changed
+ - do.name == "Small"
+ - do.display_text == "Small 10GB"
+ - do.storage_tags == ['eco', 'backup']
+ - do.storage_type == "local"
+
+- name: update disk offering idempotence
+ cs_disk_offering:
+ name: Small
+ disk_size: 10
+ display_text: Small 10GB
+ register: do
+- name: verify update disk offering idempotence
+ assert:
+ that:
+ - do is not changed
+ - do.name == "Small"
+ - do.display_text == "Small 10GB"
+ - do.storage_tags == ['eco', 'backup']
+ - do.storage_type == "local"
+
+- name: remove disk offering in check mode
+ cs_disk_offering:
+ name: Small
+ state: absent
+ check_mode: true
+ register: do
+- name: verify remove disk offering in check mode
+ assert:
+ that:
+ - do is changed
+ - do.name == "Small"
+ - do.display_text == "Small 10GB"
+ - do.storage_tags == ['eco', 'backup']
+ - do.storage_type == "local"
+
+- name: remove disk offering
+ cs_disk_offering:
+ name: Small
+ state: absent
+ register: do
+- name: verify remove disk offering
+ assert:
+ that:
+ - do is changed
+ - do.name == "Small"
+ - do.display_text == "Small 10GB"
+ - do.storage_tags == ['eco', 'backup']
+ - do.storage_type == "local"
+
+- name: remove disk offering idempotence
+ cs_disk_offering:
+ name: Small
+ state: absent
+ register: do
+- name: verify remove disk offering idempotence
+ assert:
+ that:
+ - do is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/tasks/main.yml
new file mode 100644
index 00000000..e51ca0d4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/tasks/main.yml
@@ -0,0 +1,241 @@
+---
+- name: setup
+ cs_domain:
+ path: "{{ cs_resource_prefix }}_domain"
+ state: absent
+ register: dom
+- name: verify setup
+ assert:
+ that:
+ - dom is successful
+
+- name: test fail if missing name
+ action: cs_domain
+ register: dom
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - dom is failed
+ - 'dom.msg == "missing required arguments: path"'
+
+- name: test fail if ends with /
+ cs_domain:
+ path: "{{ cs_resource_prefix }}_domain/"
+ register: dom
+ ignore_errors: true
+- name: verify results of fail if ends with /
+ assert:
+ that:
+ - dom is failed
+ - dom.msg == "Path '{{ cs_resource_prefix }}_domain/' must not end with /"
+
+- name: test create a domain in check mode
+ cs_domain:
+ path: "{{ cs_resource_prefix }}_domain"
+ register: dom
+ check_mode: true
+- name: verify results of test create a domain in check mode
+ assert:
+ that:
+ - dom is changed
+
+- name: test create a domain
+ cs_domain:
+ path: "{{ cs_resource_prefix }}_domain"
+ register: dom
+- name: verify results of test create a domain
+ assert:
+ that:
+ - dom is changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain"
+ - dom.name == "{{ cs_resource_prefix }}_domain"
+
+- name: test create a domain idempotence
+ cs_domain:
+ path: "{{ cs_resource_prefix }}_domain"
+ register: dom
+- name: verify results of test create a domain idempotence
+ assert:
+ that:
+ - dom is not changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain"
+ - dom.name == "{{ cs_resource_prefix }}_domain"
+
+- name: test create a domain idempotence2
+ cs_domain:
+ path: "/{{ cs_resource_prefix }}_domain"
+ register: dom
+- name: verify results of test create a domain idempotence2
+ assert:
+ that:
+ - dom is not changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain"
+ - dom.name == "{{ cs_resource_prefix }}_domain"
+
+- name: test fail to create a subdomain for inexistent domain
+ cs_domain:
+ path: ROOT/inexistent/{{ cs_resource_prefix }}_subdomain
+ register: dom
+ ignore_errors: true
+- name: test fail to create a subdomain for inexistent domain
+ assert:
+ that:
+ - dom is failed
+ - dom.msg == "Parent domain path ROOT/inexistent does not exist"
+
+- name: test create a subdomain in check mode
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ register: dom
+ check_mode: true
+- name: verify results of test create a domain in check mode
+ assert:
+ that:
+ - dom is changed
+
+- name: test create a subdomain
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ register: dom
+- name: verify results of test create a domain
+ assert:
+ that:
+ - dom is changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain"
+ - dom.name == "{{ cs_resource_prefix }}_subdomain"
+
+- name: test create a subdomain idempotence
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ register: dom
+- name: verify results of test create a subdomain idempotence
+ assert:
+ that:
+ - dom is not changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain"
+ - dom.name == "{{ cs_resource_prefix }}_subdomain"
+
+- name: test update a subdomain in check mode
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ network_domain: domain.example.com
+ register: dom
+ check_mode: true
+- name: verify results of test update a subdomain in check mode
+ assert:
+ that:
+ - dom is changed
+ - dom.network_domain is undefined
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain"
+ - dom.name == "{{ cs_resource_prefix }}_subdomain"
+
+- name: test update a subdomain
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ network_domain: domain.example.com
+ register: dom
+- name: verify results of test update a subdomain
+ assert:
+ that:
+ - dom is changed
+ - dom.network_domain == "domain.example.com"
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain"
+ - dom.name == "{{ cs_resource_prefix }}_subdomain"
+
+- name: test update a subdomain idempotence
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ network_domain: domain.example.com
+ register: dom
+- name: verify results of test update a subdomain idempotence
+ assert:
+ that:
+ - dom is not changed
+ - dom.network_domain == "domain.example.com"
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain"
+ - dom.name == "{{ cs_resource_prefix }}_subdomain"
+
+- name: test delete a subdomain in check mode
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ state: absent
+ register: dom
+ check_mode: true
+- name: verify results of test delete a subdomain in check mode
+ assert:
+ that:
+ - dom is changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain"
+ - dom.name == "{{ cs_resource_prefix }}_subdomain"
+
+- name: test delete a subdomain
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ state: absent
+ register: dom
+- name: verify results of test delete a subdomain
+ assert:
+ that:
+ - dom is changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain"
+ - dom.name == "{{ cs_resource_prefix }}_subdomain"
+
+- name: test delete a subdomain idempotence
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ state: absent
+ register: dom
+- name: verify results of test delete a subdomain idempotence
+ assert:
+ that:
+ - dom is not changed
+
+- name: test create a subdomain 2
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain
+ register: dom
+- name: verify results of test create a subdomain 2
+ assert:
+ that:
+ - dom is changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain"
+ - dom.name == "{{ cs_resource_prefix }}_subdomain"
+
+- name: test delete a domain with clean up in check mode
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain
+ state: absent
+ clean_up: true
+ register: dom
+ check_mode: true
+- name: verify results of test delete a domain with clean up in check mode
+ assert:
+ that:
+ - dom is changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain"
+ - dom.name == "{{ cs_resource_prefix }}_domain"
+
+- name: test delete a domain with clean up
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain
+ state: absent
+ clean_up: true
+ register: dom
+- name: verify results of test delete a domain with clean up
+ assert:
+ that:
+ - dom is changed
+ - dom.path == "ROOT/{{ cs_resource_prefix }}_domain"
+ - dom.name == "{{ cs_resource_prefix }}_domain"
+
+- name: test delete a domain with clean up idempotence
+ cs_domain:
+ path: ROOT/{{ cs_resource_prefix }}_domain
+ state: absent
+ clean_up: true
+ register: dom
+- name: verify results of test delete a domain with clean up idempotence
+ assert:
+ that:
+ - dom is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/defaults/main.yml
new file mode 100644
index 00000000..f5999305
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+cs_firewall_ip_address: 10.100.212.5
+cs_firewall_network: ansible test
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/tasks/main.yml
new file mode 100644
index 00000000..5061ef89
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/tasks/main.yml
@@ -0,0 +1,447 @@
+---
+- name: network setup
+ cs_network:
+ name: "{{ cs_firewall_network }}"
+ network_offering: DefaultIsolatedNetworkOfferingWithSourceNatService
+ network_domain: example.com
+ zone: "{{ cs_common_zone_adv }}"
+ register: net
+
+- name: setup instance to get network in implementation state
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-cs-firewall"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ networks:
+ - "{{ net.name }}"
+ register: instance
+ until: instance is success
+ retries: 20
+ delay: 5
+- name: verify instance setup
+ assert:
+ that:
+ - instance is successful
+
+- name: public ip address setup
+ cs_ip_address:
+ network: ansible test
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify public ip address setup
+ assert:
+ that:
+ - ip_address is successful
+
+- name: set ip address as fact
+ set_fact:
+ cs_firewall_ip_address: "{{ ip_address.ip_address }}"
+
+- name: setup 80
+ cs_firewall:
+ port: 80
+ ip_address: "{{ cs_firewall_ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+
+- name: setup 5300
+ cs_firewall:
+ ip_address: "{{ cs_firewall_ip_address }}"
+ protocol: udp
+ start_port: 5300
+ end_port: 5333
+ cidrs:
+ - 1.2.3.0/24
+ - 4.5.6.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+
+- name: setup all
+ cs_firewall:
+ network: "{{ cs_firewall_network }}"
+ protocol: all
+ type: egress
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+
+- name: test fail if missing params
+ action: cs_firewall
+ register: fw
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - fw is failed
+ - "fw.msg == 'one of the following is required: ip_address, network'"
+
+- name: test fail if missing params
+ cs_firewall:
+ ip_address: "{{ cs_firewall_ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - fw is failed
+ - "fw.msg == \"missing required argument for protocol 'tcp': start_port or end_port\""
+
+- name: test fail if missing params network egress
+ cs_firewall:
+ type: egress
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+ ignore_errors: true
+- name: verify results of fail if missing params ip_address
+ assert:
+ that:
+ - fw is failed
+ - "fw.msg == 'one of the following is required: ip_address, network'"
+
+- name: test present firewall rule ingress 80 in check mode
+ cs_firewall:
+ port: 80
+ ip_address: "{{ cs_firewall_ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+ check_mode: true
+- name: verify results of present firewall rule ingress 80 in check mode
+ assert:
+ that:
+ - fw is changed
+
+- name: test present firewall rule ingress 80
+ cs_firewall:
+ port: 80
+ ip_address: "{{ cs_firewall_ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+- name: verify results of present firewall rule ingress 80
+ assert:
+ that:
+ - fw is changed
+ - fw.cidr == "0.0.0.0/0"
+ - fw.cidrs == [ '0.0.0.0/0' ]
+ - fw.ip_address == "{{ cs_firewall_ip_address }}"
+ - fw.protocol == "tcp"
+ - fw.start_port == 80
+ - fw.end_port == 80
+ - fw.type == "ingress"
+
+- name: test present firewall rule ingress 80 idempotence
+ cs_firewall:
+ port: 80
+ ip_address: "{{ cs_firewall_ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+- name: verify results of present firewall rule ingress 80 idempotence
+ assert:
+ that:
+ - fw is not changed
+ - fw.cidr == "0.0.0.0/0"
+ - fw.cidrs == [ '0.0.0.0/0' ]
+ - fw.ip_address == "{{ cs_firewall_ip_address }}"
+ - fw.protocol == "tcp"
+ - fw.start_port == 80
+ - fw.end_port == 80
+ - fw.type == "ingress"
+
+- name: test present firewall rule ingress 5300 in check mode
+ cs_firewall:
+ ip_address: "{{ cs_firewall_ip_address }}"
+ protocol: udp
+ start_port: 5300
+ end_port: 5333
+ cidrs:
+ - 1.2.3.0/24
+ - 4.5.6.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+ check_mode: true
+- name: verify results of present firewall rule ingress 5300 in check mode
+ assert:
+ that:
+ - fw is changed
+
+- name: test present firewall rule ingress 5300
+ cs_firewall:
+ ip_address: "{{ cs_firewall_ip_address }}"
+ protocol: udp
+ start_port: 5300
+ end_port: 5333
+ cidrs:
+ - 1.2.3.0/24
+ - 4.5.6.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+- name: verify results of present firewall rule ingress 5300
+ assert:
+ that:
+ - fw is changed
+ - fw.cidr == "1.2.3.0/24,4.5.6.0/24"
+ - fw.cidrs == [ '1.2.3.0/24', '4.5.6.0/24' ]
+ - fw.ip_address == "{{ cs_firewall_ip_address }}"
+ - fw.protocol == "udp"
+ - fw.start_port == 5300
+ - fw.end_port == 5333
+ - fw.type == "ingress"
+
+- name: test present firewall rule ingress 5300 idempotence
+ cs_firewall:
+ ip_address: "{{ cs_firewall_ip_address }}"
+ protocol: udp
+ start_port: 5300
+ end_port: 5333
+ cidrs:
+ - 1.2.3.0/24
+ - 4.5.6.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+- name: verify results of present firewall rule ingress 5300 idempotence
+ assert:
+ that:
+ - fw is not changed
+ - fw.cidr == "1.2.3.0/24,4.5.6.0/24"
+ - fw.cidrs == [ '1.2.3.0/24', '4.5.6.0/24' ]
+ - fw.ip_address == "{{ cs_firewall_ip_address }}"
+ - fw.protocol == "udp"
+ - fw.start_port == 5300
+ - fw.end_port == 5333
+ - fw.type == "ingress"
+
+- name: test present firewall rule egress all in check mode
+ cs_firewall:
+ network: "{{ cs_firewall_network }}"
+ protocol: all
+ type: egress
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+ check_mode: true
+- name: verify results of present firewall rule egress all in check mode
+ assert:
+ that:
+ - fw is changed
+
+- name: test present firewall rule egress all
+ cs_firewall:
+ network: "{{ cs_firewall_network }}"
+ protocol: all
+ type: egress
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+- name: verify results of present firewall rule egress all
+ assert:
+ that:
+ - fw is changed
+ - fw.cidr == "0.0.0.0/0" or fw.cidr == "10.1.1.0/24"
+ - fw.cidrs == [ '0.0.0.0/0' ] or fw.cidrs == [ '10.1.1.0/24' ]
+ - fw.network == "{{ cs_firewall_network }}"
+ - fw.protocol == "all"
+ - fw.type == "egress"
+
+- name: test present firewall rule egress all idempotence
+ cs_firewall:
+ network: "{{ cs_firewall_network }}"
+ protocol: all
+ type: egress
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+- name: verify results of present firewall rule egress all idempotence
+ assert:
+ that:
+ - fw is not changed
+ - fw.cidr == "0.0.0.0/0" or fw.cidr == "10.1.1.0/24"
+ - fw.cidrs == [ '0.0.0.0/0' ] or fw.cidrs == [ '10.1.1.0/24' ]
+ - fw.network == "{{ cs_firewall_network }}"
+ - fw.protocol == "all"
+ - fw.type == "egress"
+
+- name: test absent firewall rule ingress 80 in check mode
+ cs_firewall:
+ port: 80
+ ip_address: "{{ cs_firewall_ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: fw
+ check_mode: true
+- name: verify results of absent firewall rule ingress 80 in check mode
+ assert:
+ that:
+ - fw is changed
+ - fw.cidr == "0.0.0.0/0"
+ - fw.cidrs == [ '0.0.0.0/0' ]
+ - fw.ip_address == "{{ cs_firewall_ip_address }}"
+ - fw.protocol == "tcp"
+ - fw.start_port == 80
+ - fw.end_port == 80
+ - fw.type == "ingress"
+
+- name: test absent firewall rule ingress 80
+ cs_firewall:
+ port: 80
+ ip_address: "{{ cs_firewall_ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: fw
+- name: verify results of absent firewall rule ingress 80
+ assert:
+ that:
+ - fw is changed
+ - fw.cidr == "0.0.0.0/0"
+ - fw.cidrs == [ '0.0.0.0/0' ]
+ - fw.ip_address == "{{ cs_firewall_ip_address }}"
+ - fw.protocol == "tcp"
+ - fw.start_port == 80
+ - fw.end_port == 80
+ - fw.type == "ingress"
+
+- name: test absent firewall rule ingress 80 idempotence
+ cs_firewall:
+ port: 80
+ ip_address: "{{ cs_firewall_ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: fw
+- name: verify results of absent firewall rule ingress 80 idempotence
+ assert:
+ that:
+ - fw is not changed
+
+- name: test absent firewall rule ingress 5300 in check mode
+ cs_firewall:
+ ip_address: "{{ cs_firewall_ip_address }}"
+ protocol: udp
+ start_port: 5300
+ end_port: 5333
+ cidrs:
+ - 1.2.3.0/24
+ - 4.5.6.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: fw
+ check_mode: true
+- name: verify results of absent firewall rule ingress 5300 in check mode
+ assert:
+ that:
+ - fw is changed
+ - fw.cidr == "1.2.3.0/24,4.5.6.0/24"
+ - fw.cidrs == [ '1.2.3.0/24', '4.5.6.0/24' ]
+ - fw.ip_address == "{{ cs_firewall_ip_address }}"
+ - fw.protocol == "udp"
+ - fw.start_port == 5300
+ - fw.end_port == 5333
+ - fw.type == "ingress"
+
+- name: test absent firewall rule ingress 5300
+ cs_firewall:
+ ip_address: "{{ cs_firewall_ip_address }}"
+ protocol: udp
+ start_port: 5300
+ end_port: 5333
+ cidrs:
+ - 1.2.3.0/24
+ - 4.5.6.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: fw
+- name: verify results of absent firewall rule ingress 5300
+ assert:
+ that:
+ - fw is changed
+ - fw.cidr == "1.2.3.0/24,4.5.6.0/24"
+ - fw.cidrs == [ '1.2.3.0/24', '4.5.6.0/24' ]
+ - fw.ip_address == "{{ cs_firewall_ip_address }}"
+ - fw.protocol == "udp"
+ - fw.start_port == 5300
+ - fw.end_port == 5333
+ - fw.type == "ingress"
+
+- name: test absent firewall rule ingress 5300 idempotence
+ cs_firewall:
+ ip_address: "{{ cs_firewall_ip_address }}"
+ protocol: udp
+ start_port: 5300
+ end_port: 5333
+ cidrs:
+ - 1.2.3.0/24
+ - 4.5.6.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: fw
+- name: verify results of absent firewall rule ingress 5300 idempotence
+ assert:
+ that:
+ - fw is not changed
+
+- name: test absent firewall rule egress all in check mode
+ cs_firewall:
+ network: "{{ cs_firewall_network }}"
+ protocol: all
+ type: egress
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+ check_mode: true
+- name: verify results of absent firewall rule egress all in check mode
+ assert:
+ that:
+ - fw is changed
+ - fw.cidr == "0.0.0.0/0" or fw.cidr == "10.1.1.0/24"
+ - fw.cidrs == [ '0.0.0.0/0' ] or fw.cidrs == [ '10.1.1.0/24' ]
+ - fw.network == "{{ cs_firewall_network }}"
+ - fw.protocol == "all"
+ - fw.type == "egress"
+
+- name: test absent firewall rule egress all
+ cs_firewall:
+ network: "{{ cs_firewall_network }}"
+ protocol: all
+ type: egress
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: fw
+- name: verify results of absent firewall rule egress all
+ assert:
+ that:
+ - fw is changed
+ - fw.cidr == "0.0.0.0/0" or fw.cidr == "10.1.1.0/24"
+ - fw.cidrs == [ '0.0.0.0/0' ] or fw.cidrs == [ '10.1.1.0/24' ]
+ - fw.network == "{{ cs_firewall_network }}"
+ - fw.protocol == "all"
+ - fw.type == "egress"
+
+- name: test absent firewall rule egress all idempotence
+ cs_firewall:
+ network: "{{ cs_firewall_network }}"
+ protocol: all
+ type: egress
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: fw
+- name: verify results of absent firewall rule egress all idempotence
+ assert:
+ that:
+ - fw is not changed
+
+- name: cleanup instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-cs-firewall"
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+ register: instance
+- name: verify instance cleanup
+ assert:
+ that:
+ - instance is successful
+
+- name: network cleanup
+ cs_network:
+ name: "{{ cs_firewall_network }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: net
+- name: verify network cleanup
+ assert:
+ that:
+ - net is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/tasks/main.yml
new file mode 100644
index 00000000..c47d006d
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/tasks/main.yml
@@ -0,0 +1,438 @@
+---
+- name: test fail missing params
+ cs_host:
+ zone: "{{ cs_common_zone_basic }}"
+ register: host
+ ignore_errors: true
+- name: verify test fail missing url if host is not existent
+ assert:
+ that:
+ - host is failed
+ - 'host.msg == "missing required arguments: name"'
+
+- name: test fail missing params if host is not existent
+ cs_host:
+ name: sim
+ zone: "{{ cs_common_zone_basic }}"
+ register: host
+ ignore_errors: true
+- name: verify test fail missing params if host is not existent
+ assert:
+ that:
+ - host is failed
+ - 'host.msg == "missing required arguments: password, username, hypervisor, pod"'
+
+- name: test create a host in check mode
+ cs_host:
+ name: sim
+ zone: "{{ cs_common_zone_basic }}"
+ url: "http://sim/c0-basic/h2"
+ cluster: C0-basic
+ pod: POD0-basic
+ username: root
+ password: password
+ hypervisor: Simulator
+ allocation_state: enabled
+ host_tags:
+ - perf
+ - gpu
+ register: host
+ check_mode: true
+- name: verify test create a host in check mode
+ assert:
+ that:
+ - host is changed
+
+- name: test create a host
+ cs_host:
+ name: sim
+ zone: "{{ cs_common_zone_basic }}"
+ url: "http://sim/c0-basic/h2"
+ cluster: C0-basic
+ pod: POD0-basic
+ username: root
+ password: password
+ hypervisor: Simulator
+ allocation_state: enabled
+ host_tags:
+ - perf
+ - gpu
+ register: host
+- name: verify test create a host
+ assert:
+ that:
+ - host is changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - "host.name.startswith('SimulatedAgent.')"
+ - host.host_tags == ['perf', 'gpu']
+
+# This is special in simulator mode, we can not predict the full hostname.
+# That is why we gather the infos from the returns and use a fact.
+- name: assume the sim would resolve to the IP address
+ set_fact:
+ host_hostname: "{{ host.name }}"
+ host_ip_address: "{{ host.ip_address }}"
+
+- name: test create a host idempotence
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ url: "http://sim/c0-basic/h2"
+ cluster: C0-basic
+ pod: POD0-basic
+ username: admin
+ password: password
+ hypervisor: Simulator
+ allocation_state: enabled
+ host_tags:
+ - perf
+ - gpu
+ register: host
+- name: verify test create a host idempotence
+ assert:
+ that:
+ - host is not changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu']
+
+- name: test update host in check mode
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ url: "http://sim/c0-basic/h2"
+ cluster: C0-basic
+ pod: POD0-basic
+ username: admin
+ password: password
+ hypervisor: Simulator
+ allocation_state: enabled
+ host_tags:
+ - perf
+ - gpu
+ - x2
+ register: host
+ check_mode: true
+- name: verify test update a host in check mode
+ assert:
+ that:
+ - host is changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu']
+
+- name: test update host
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ url: "http://sim/c0-basic/h2"
+ cluster: C0-basic
+ pod: POD0-basic
+ username: admin
+ password: password
+ hypervisor: Simulator
+ allocation_state: enabled
+ host_tags:
+ - perf
+ - gpu
+ - x2
+ register: host
+- name: verify test update a host in check mode
+ assert:
+ that:
+ - host is changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+- name: test update host idempotence
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ url: "http://sim/c0-basic/h2"
+ cluster: C0-basic
+ pod: POD0-basic
+ username: admin
+ password: password
+ hypervisor: Simulator
+ allocation_state: enabled
+ host_tags:
+ - perf
+ - gpu
+ - x2
+ register: host
+- name: verify test update a host idempotence
+ assert:
+ that:
+ - host is not changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+# FIXME: Removing by empty list seems to be an issue in the used lib cs underneath, disabled
+- name: test update host remove host_tags
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ url: "http://sim/c0-basic/h2"
+ cluster: C0-basic
+ pod: POD0-basic
+ username: admin
+ password: password
+ hypervisor: Simulator
+ allocation_state: enabled
+ host_tags: []
+ register: host
+ when: false
+- name: verify test update host remove host_tags
+ assert:
+ that:
+ - host is changed
+ - host.host_tags|length == 0
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ when: false
+
+# FIXME: Removing by empty list seems to be an issue in the used lib cs underneath, disabled
+- name: test update host remove host_tags idempotence
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ url: "http://sim/c0-basic/h2"
+ cluster: C0-basic
+ pod: POD0-basic
+ username: admin
+ password: password
+ hypervisor: Simulator
+ allocation_state: enabled
+ host_tags: []
+ register: host
+ when: false
+- name: verify test update host remove host_tags idempotence
+ assert:
+ that:
+ - host is not changed
+ - len(host.host_tags) == 0
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ when: false
+
+
+- name: test put host in maintenance in check mode
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ cluster: C0-basic
+ pod: POD0-basic
+ allocation_state: maintenance
+ check_mode: true
+ register: host
+- name: verify test put host in maintenance in check mode
+ assert:
+ that:
+ - host is changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+- name: test put host in maintenance
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ cluster: C0-basic
+ pod: POD0-basic
+ allocation_state: maintenance
+ register: host
+- name: verify test put host in maintenance
+ assert:
+ that:
+ - host is changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'maintenance'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+- name: test put host in maintenance idempotence
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ cluster: C0-basic
+ pod: POD0-basic
+ allocation_state: maintenance
+ register: host
+- name: verify test put host in maintenance idempotence
+ assert:
+ that:
+ - host is not changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'maintenance'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+- name: test put host out of maintenance in check mode
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ cluster: C0-basic
+ pod: POD0-basic
+ allocation_state: enabled
+ check_mode: true
+ register: host
+- name: verify test put host out of maintenance in check mode
+ assert:
+ that:
+ - host is changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'maintenance'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+- name: test put host out of maintenance
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ cluster: C0-basic
+ pod: POD0-basic
+ allocation_state: enabled
+ register: host
+- name: verify test put host out of maintenance
+ assert:
+ that:
+ - host is changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+- name: test put host out of maintenance idempotence
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ cluster: C0-basic
+ pod: POD0-basic
+ allocation_state: enabled
+ register: host
+- name: verify test put host out of maintenance idempotence
+ assert:
+ that:
+ - host is not changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+- name: test remove host in check mode
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ cluster: C0-basic
+ pod: POD0-basic
+ state: absent
+ check_mode: true
+ register: host
+- name: verify test remove a host in check mode
+ assert:
+ that:
+ - host is changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+- name: test remove host
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ cluster: C0-basic
+ pod: POD0-basic
+ state: absent
+ register: host
+- name: verify test remove a host
+ assert:
+ that:
+ - host is changed
+ - host.cluster == 'C0-basic'
+ - host.pod == 'POD0-basic'
+ - host.hypervisor == 'Simulator'
+ - host.allocation_state == 'enabled'
+ - host.zone == 'Sandbox-simulator-basic'
+ - host.state == 'Up'
+ - host.name == '{{ host_hostname }}'
+ - host.host_tags == ['perf', 'gpu', 'x2']
+
+- name: test remove host idempotence
+ cs_host:
+ name: "{{ host_hostname }}"
+ zone: "{{ cs_common_zone_basic }}"
+ cluster: C0-basic
+ pod: POD0-basic
+ state: absent
+ register: host
+- name: verify test remove a host idempotenc
+ assert:
+ that:
+ - host is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/tasks/main.yml
new file mode 100644
index 00000000..8d1eaa07
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/tasks/main.yml
@@ -0,0 +1,166 @@
+---
+- name: setup image store is absent
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sp
+- name: verify setup image store is absent
+ assert:
+ that:
+ - sp is successful
+
+- name: test fail if missing params
+ cs_image_store:
+ register: ss
+ ignore_errors: true
+- name: verify test fail if missing params
+ assert:
+ that:
+ - ss is failed
+ - "'name' in ss.msg"
+ - "'zone' in ss.msg"
+ - "'missing required arguments: ' in ss.msg"
+
+- name: setup image store with wrong parameters
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: present
+ ignore_errors: true
+ register: ss
+- name: verify setup image store with wrong parameters
+ assert:
+ that:
+ - ss is failed
+ - "ss.msg == 'state is present but all of the following are missing: url, provider'"
+
+- name: setup image store in check mode
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ url: "nfs://nfs-mount.domain/share/images/"
+ provider: "NFS"
+ state: present
+ check_mode: true
+ register: ss
+- name: verify setup image store in check mode
+ assert:
+ that:
+ - ss is successful
+ - ss is changed
+
+- name: setup image store
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ url: "nfs://nfs-mount.domain/share/images/"
+ provider: "NFS"
+ state: present
+ register: ss
+- name: verify setup image store
+ assert:
+ that:
+ - ss is successful
+ - ss is changed
+ - "ss.url == 'nfs://nfs-mount.domain/share/images/'"
+ - "ss.provider_name == 'NFS'"
+ - "ss.zone == cs_common_zone_adv"
+ - "ss.protocol == 'nfs'"
+
+- name: setup image store idempotence
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ url: "nfs://nfs-mount.domain/share/images/"
+ provider: "NFS"
+ state: present
+ register: ss
+- name: verify setup image store idempotence
+ assert:
+ that:
+ - ss is successful
+ - ss is not changed
+ - "ss.url == 'nfs://nfs-mount.domain/share/images/'"
+ - "ss.provider_name == 'NFS'"
+ - "ss.zone == cs_common_zone_adv"
+ - "ss.protocol == 'nfs'"
+ - "ss.name == 'storage_pool_adv'"
+
+- name: image store not recreated
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ url: "nfs://nfs-mount.domain/share2/images/"
+ provider: "NFS"
+ state: present
+ register: ss
+- name: verify image store not recreated
+ assert:
+ that:
+ - ss is successful
+ - ss is not changed
+ - "ss.url == 'nfs://nfs-mount.domain/share/images/'"
+ - "ss.name == 'storage_pool_adv'"
+ - "ss.zone == cs_common_zone_adv"
+
+- name: recreate image store
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ url: "nfs://nfs-mount.domain/share2/images/"
+ provider: "NFS"
+ force_recreate: yes
+ state: present
+ register: ss
+- name: verify setup image store idempotence
+ assert:
+ that:
+ - ss is successful
+ - ss is changed
+ - "ss.url == 'nfs://nfs-mount.domain/share2/images/'"
+ - "ss.name == 'storage_pool_adv'"
+ - "ss.zone == cs_common_zone_adv"
+
+- name: delete the image store in check_mode
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: ss
+ check_mode: yes
+- name: verify results for delete the image store in check_mode
+ assert:
+ that:
+ - ss is successful
+ - ss is changed
+ - "ss.name == 'storage_pool_adv'"
+ - "ss.zone == cs_common_zone_adv"
+
+- name: delete the image store
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: ss
+- name: verify results for delete the image store
+ assert:
+ that:
+ - ss is successful
+ - ss is changed
+ - "ss.name == 'storage_pool_adv'"
+ - "ss.zone == cs_common_zone_adv"
+
+- name: delete the image store idempotence
+ cs_image_store:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: ss
+- name: verify delete the image store idempotence
+ assert:
+ that:
+ - ss is successful
+ - ss is not changed
+ - ss.name is undefined
+ - "ss.zone == cs_common_zone_adv" \ No newline at end of file
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/defaults/main.yml
new file mode 100644
index 00000000..4db5c7c9
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+instance_number: 1
+test_cs_instance_template: "{{ cs_common_template }}"
+test_cs_instance_offering_1: Small Instance
+test_cs_instance_offering_2: Medium Instance
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent.yml
new file mode 100644
index 00000000..ea94b4d8
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent.yml
@@ -0,0 +1,124 @@
+---
+- name: test destroy instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: instance
+ check_mode: true
+- name: verify destroy instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state != "Destroyed"
+
+- name: test destroy instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: instance
+- name: verify destroy instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Destroyed"
+
+- name: test destroy instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: instance
+- name: verify destroy instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+
+- name: test recover to stopped state and update a deleted instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ state: stopped
+ register: instance
+ check_mode: true
+- name: verify test recover to stopped state and update a deleted instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+
+- name: test recover to stopped state and update a deleted instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ state: stopped
+ register: instance
+- name: verify test recover to stopped state and update a deleted instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Stopped"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test recover to stopped state and update a deleted instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ state: stopped
+ register: instance
+- name: verify test recover to stopped state and update a deleted instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.state == "Stopped"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test expunge instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: expunged
+ register: instance
+ check_mode: true
+- name: verify test expunge instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Stopped"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test expunge instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: expunged
+ register: instance
+- name: verify test expunge instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Stopped"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test expunge instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: expunged
+ register: instance
+- name: verify test expunge instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent_display_name.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent_display_name.yml
new file mode 100644
index 00000000..8bea0ae4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent_display_name.yml
@@ -0,0 +1,47 @@
+---
+- name: test destroy instance with display_name
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: instance
+- name: verify destroy instance with display_name
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Destroyed"
+
+- name: test destroy instance with display_name idempotence
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: instance
+- name: verify destroy instance with display_name idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+
+- name: test recover to stopped state and update a deleted instance with display_name
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ state: stopped
+ register: instance
+- name: verify test recover to stopped state and update a deleted instance with display_name
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Stopped"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+# force expunge, only works with admin permissions
+- cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: expunged
+ failed_when: false
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/cleanup.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/cleanup.yml
new file mode 100644
index 00000000..655aab60
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/cleanup.yml
@@ -0,0 +1,36 @@
+---
+- name: cleanup ssh key
+ cs_sshkeypair:
+ name: "{{ cs_resource_prefix }}-sshkey"
+ state: absent
+ register: sshkey
+- name: verify cleanup ssh key
+ assert:
+ that:
+ - sshkey is successful
+
+- name: cleanup affinity group
+ cs_affinitygroup:
+ name: "{{ cs_resource_prefix }}-ag"
+ state: absent
+ register: ag
+ until: ag is successful
+ retries: 20
+ delay: 5
+- name: verify cleanup affinity group
+ assert:
+ that:
+ - ag is successful
+
+- name: cleanup security group ...take a while unless instance is expunged
+ cs_securitygroup:
+ name: "{{ cs_resource_prefix }}-sg"
+ state: absent
+ register: sg
+ until: sg is successful
+ retries: 100
+ delay: 10
+- name: verify cleanup security group
+ assert:
+ that:
+ - sg is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/host.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/host.yml
new file mode 100644
index 00000000..5d4a89c2
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/host.yml
@@ -0,0 +1,143 @@
+---
+- name: setup ensure running instance to get host infos
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ state: started
+ register: running_instance
+
+- name: setup ensure stopped instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: stopped
+
+- name: setup zone facts
+ cs_zone_info:
+ name: "{{ cs_common_zone_basic }}"
+ register: zone_info
+
+- name: setup find the host name
+ shell: cs listHosts type=routing zoneid="{{ zone_info.zones[0].id }}"
+ args:
+ chdir: "{{ playbook_dir }}"
+ register: host
+
+- name: host convert from json
+ set_fact:
+ host_json: "{{ host.stdout | from_json }}"
+
+- name: select a host on which the instance was not running on
+ set_fact:
+ host: "{{ host_json | json_query('host[?name!=`' + running_instance.host + '`] | [0]') }}"
+
+- debug:
+ msg: "from current host {{ running_instance.host }} to new host {{ host.name }}"
+
+- name: test starting instance on new host in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ host: "{{ host.name }}"
+ state: started
+ register: instance
+ check_mode: true
+- name: verify test starting instance on new host in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.host is not defined
+ - instance.state == "Stopped"
+
+- name: test starting instance on new host
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ host: "{{ host.name }}"
+ state: started
+ register: instance
+- name: verify test starting instance on new host
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.host == "{{ host.name }}"
+ - instance.state == "Running"
+
+- name: test starting instance on new host idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ host: "{{ host.name }}"
+ state: started
+ register: instance
+- name: verify test starting instance on new host idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.host == "{{ host.name }}"
+ - instance.state == "Running"
+
+- name: select a host on which the instance is not running on
+ set_fact:
+ host: "{{ host_json | json_query('host[?name!=`' + instance.host + '`] | [0]') }}"
+
+- debug:
+ msg: "from current host {{ instance.host }} to new host {{ host.name }}"
+
+- name: test force update running instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ host: "{{ host.name }}"
+ force: true
+ register: instance
+ check_mode: true
+- name: verify force update running instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.host != "{{ host.name }}"
+ - instance.state == "Running"
+
+- name: test force update running instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ host: "{{ host.name }}"
+ force: true
+ register: instance
+- name: verify force update running instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.host == "{{ host.name }}"
+ - instance.state == "Running"
+
+- name: test force update running instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ host: "{{ host.name }}"
+ force: true
+ register: instance
+- name: verify force update running instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.host == "{{ host.name }}"
+ - instance.state == "Running"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/main.yml
new file mode 100644
index 00000000..681e60ab
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/main.yml
@@ -0,0 +1,19 @@
+---
+- import_tasks: setup.yml
+
+- import_tasks: present.yml
+- import_tasks: tags.yml
+- import_tasks: absent.yml
+
+- import_tasks: present_display_name.yml
+- import_tasks: absent_display_name.yml
+
+# TODO: These tests randomly fail in all kinds of unexpected states.
+# This needs to be verified by the cloudstack community.
+# - import_tasks: host.yml
+
+- import_tasks: sshkeys.yml
+
+- import_tasks: project.yml
+
+- import_tasks: cleanup.yml
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present.yml
new file mode 100644
index 00000000..b800945f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present.yml
@@ -0,0 +1,342 @@
+---
+- name: setup instance to be absent
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: expunged
+ register: instance
+- name: verify instance to be absent
+ assert:
+ that:
+ - instance is successful
+
+- name: test create instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ affinity_group: "{{ cs_resource_prefix }}-ag"
+ security_group: "{{ cs_resource_prefix }}-sg"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey"
+ user_data: |
+ #cloud-config
+ package_upgrade: true
+ packages:
+ - tmux
+ tags: []
+ register: instance
+ check_mode: true
+- name: verify create instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+
+- name: test create instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ affinity_group: "{{ cs_resource_prefix }}-ag"
+ security_group: "{{ cs_resource_prefix }}-sg"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey"
+ user_data: |
+ #cloud-config
+ package_upgrade: true
+ packages:
+ - tmux
+ tags: []
+ register: instance
+- name: verify create instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey"
+ - not instance.tags
+
+- name: test create instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ affinity_group: "{{ cs_resource_prefix }}-ag"
+ security_group: "{{ cs_resource_prefix }}-sg"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey"
+ user_data: |
+ #cloud-config
+ package_upgrade: true
+ packages:
+ - tmux
+ tags: []
+ register: instance
+- name: verify create instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey"
+ - not instance.tags
+
+- name: gather host infos of running instance
+ cs_instance_info:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+
+- name: test running instance not updated in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+ check_mode: true
+- name: verify running instance not updated in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test running instance not updated
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+- name: verify running instance not updated
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test stopping instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: stopped
+ register: instance
+ check_mode: true
+- name: verify stopping instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test stopping instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: stopped
+ register: instance
+- name: verify stopping instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Stopped"
+
+- name: test stopping instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: stopped
+ register: instance
+- name: verify stopping instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.state == "Stopped"
+
+- name: test updating stopped instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+ check_mode: true
+- name: verify updating stopped instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Stopped"
+
+- name: test updating stopped instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+- name: verify updating stopped instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Stopped"
+
+- name: test updating stopped instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+- name: verify updating stopped instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Stopped"
+
+- name: test starting instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: started
+ register: instance
+- name: verify starting instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Running"
+
+- name: test starting instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: started
+ register: instance
+- name: verify starting instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Running"
+
+- name: test force update running instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ force: true
+ register: instance
+ check_mode: true
+- name: verify force update running instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Running"
+
+- name: test force update running instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ force: true
+ register: instance
+- name: verify force update running instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test force update running instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ force: true
+ register: instance
+- name: verify force update running instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test restore instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ state: restored
+ register: instance
+ check_mode: true
+- name: verify restore instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test restore instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ state: restored
+ register: instance
+- name: verify restore instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present_display_name.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present_display_name.yml
new file mode 100644
index 00000000..1daa4c7f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present_display_name.yml
@@ -0,0 +1,190 @@
+---
+- name: setup instance with display_name to be absent
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: expunged
+ register: instance
+- name: verify instance with display_name to be absent
+ assert:
+ that:
+ - instance is successful
+
+- name: test create instance with display_name
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ affinity_group: "{{ cs_resource_prefix }}-ag"
+ security_group: "{{ cs_resource_prefix }}-sg"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey"
+ tags: []
+ register: instance
+- name: verify create instance with display_name
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey"
+ - not instance.tags
+
+- name: test create instance with display_name idempotence
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ affinity_group: "{{ cs_resource_prefix }}-ag"
+ security_group: "{{ cs_resource_prefix }}-sg"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey"
+ tags: []
+ register: instance
+- name: verify create instance with display_name idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey"
+ - not instance.tags
+
+- name: test running instance with display_name not updated
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+- name: verify running instance with display_name not updated
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test stopping instance with display_name
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: stopped
+ register: instance
+- name: verify stopping instance with display_name
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Stopped"
+
+- name: test stopping instance with display_name idempotence
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: stopped
+ register: instance
+- name: verify stopping instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.state == "Stopped"
+
+- name: test updating stopped instance with display_name
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+- name: verify updating stopped instance with display_name
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Stopped"
+
+- name: test starting instance with display_name
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: started
+ register: instance
+- name: verify starting instance with display_name
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Running"
+
+- name: test starting instance with display_name idempotence
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: started
+ register: instance
+- name: verify starting instance with display_name idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Running"
+
+- name: test force update running instance with display_name
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ force: true
+ register: instance
+- name: verify force update running instance with display_name
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test force update running instance with display_name idempotence
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ force: true
+ register: instance
+- name: verify force update running instance with display_name idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test restore instance with display_name
+ cs_instance:
+ display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ state: restored
+ register: instance
+- name: verify restore instance with display_name
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/project.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/project.yml
new file mode 100644
index 00000000..edb5abf5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/project.yml
@@ -0,0 +1,589 @@
+---
+- name: setup create project
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ register: prj
+- name: verify test create project
+ assert:
+ that:
+ - prj is successful
+
+- name: setup instance in project to be absent
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: instance
+- name: verify instance in project to be absent
+ assert:
+ that:
+ - instance is successful
+
+- name: setup ssh key in project
+ cs_sshkeypair:
+ name: "{{ cs_resource_prefix }}-sshkey-prj"
+ project: "{{ cs_resource_prefix }}-prj"
+ register: sshkey
+- name: verify setup ssh key in project
+ assert:
+ that:
+ - sshkey is successful
+
+- name: setup affinity group in project
+ cs_affinitygroup:
+ name: "{{ cs_resource_prefix }}-ag-prj"
+ project: "{{ cs_resource_prefix }}-prj"
+ register: ag
+- name: verify setup affinity group in project
+ assert:
+ that:
+ - ag is successful
+
+- name: setup security group in project
+ cs_securitygroup:
+ name: "{{ cs_resource_prefix }}-sg-prj"
+ project: "{{ cs_resource_prefix }}-prj"
+ register: sg
+- name: verify setup security group in project
+ assert:
+ that:
+ - sg is successful
+
+- name: test create instance in project in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ affinity_group: "{{ cs_resource_prefix }}-ag-prj"
+ security_group: "{{ cs_resource_prefix }}-sg-prj"
+ project: "{{ cs_resource_prefix }}-prj"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey-prj"
+ tags: []
+ register: instance
+ check_mode: true
+- name: verify create instance in project in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+
+- name: test create instance in project
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ affinity_group: "{{ cs_resource_prefix }}-ag-prj"
+ security_group: "{{ cs_resource_prefix }}-sg-prj"
+ project: "{{ cs_resource_prefix }}-prj"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey-prj"
+ tags: []
+ register: instance
+- name: verify create instance in project
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey-prj"
+ - not instance.tags
+
+- name: test create instance in project idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ affinity_group: "{{ cs_resource_prefix }}-ag-prj"
+ security_group: "{{ cs_resource_prefix }}-sg-prj"
+ project: "{{ cs_resource_prefix }}-prj"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey-prj"
+ tags: []
+ register: instance
+- name: verify create instance in project idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey-prj"
+ - not instance.tags
+
+- name: test running instance in project not updated in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ register: instance
+ check_mode: true
+- name: verify running instance in project not updated in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+
+- name: test running instance in project not updated
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ register: instance
+- name: verify running instance in project not updated
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test stopping instance in project in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: stopped
+ register: instance
+ check_mode: true
+- name: verify stopping instance in project in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test stopping instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: stopped
+ register: instance
+- name: verify stopping instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Stopped"
+
+- name: test stopping instance in project idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: stopped
+ register: instance
+- name: verify stopping instance in project idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.state == "Stopped"
+
+- name: test updating stopped instance in project in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+ check_mode: true
+- name: verify updating stopped instance in project in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Stopped"
+
+- name: test updating stopped instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+- name: verify updating stopped instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Stopped"
+
+- name: test updating stopped instance in project idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ service_offering: "{{ test_cs_instance_offering_2 }}"
+ register: instance
+- name: verify updating stopped instance in project idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Stopped"
+
+- name: test starting instance in project in check mdoe
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: started
+ register: instance
+ check_mode: true
+- name: verify starting instance in project in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Stopped"
+
+- name: test starting instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: started
+ register: instance
+- name: verify starting instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Running"
+
+- name: test starting instance in project idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: started
+ register: instance
+- name: verify starting instance in project idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Running"
+
+- name: test force update running instance in project in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ force: true
+ register: instance
+ check_mode: true
+- name: verify force update running instance in project in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_2 }}"
+ - instance.state == "Running"
+
+- name: test force update running instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ force: true
+ register: instance
+- name: verify force update running instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test force update running instance in project idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ force: true
+ register: instance
+- name: verify force update running instance in project idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+ - instance.state == "Running"
+
+- name: test restore instance in project in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: restored
+ register: instance
+ check_mode: true
+- name: verify restore instance in project in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test restore instance in project
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: restored
+ register: instance
+- name: verify restore instance in project
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ - instance.project == "{{ cs_resource_prefix }}-prj"
+ - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test destroy instance in project in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: instance
+ check_mode: true
+- name: verify destroy instance in project in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state != "Destroyed"
+
+- name: test destroy instance in project
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: instance
+- name: verify destroy instance in project
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Destroyed"
+
+- name: test destroy instance in project idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: instance
+- name: verify destroy instance in project idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+
+- name: test recover in project to stopped state and update a deleted instance in project in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ state: stopped
+ register: instance
+ check_mode: true
+- name: verify test recover to stopped state and update a deleted instance in project in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+
+- name: test recover to stopped state and update a deleted instance in project
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ state: stopped
+ register: instance
+- name: verify test recover to stopped state and update a deleted instance in project
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Stopped"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test recover to stopped state and update a deleted instance in project idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ state: stopped
+ register: instance
+- name: verify test recover to stopped state and update a deleted instance in project idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.state == "Stopped"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test expunge instance in project in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: expunged
+ register: instance
+ check_mode: true
+- name: verify test expunge instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Stopped"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test expunge instance in project
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: expunged
+ register: instance
+- name: verify test expunge instance in project
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.state == "Stopped"
+ - instance.service_offering == "{{ test_cs_instance_offering_1 }}"
+
+- name: test expunge instance in project idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: expunged
+ register: instance
+- name: verify test expunge instance in project idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+
+- name: cleanup ssh key in project
+ cs_sshkeypair:
+ name: "{{ cs_resource_prefix }}-sshkey-prj"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: sshkey
+- name: verify cleanup ssh key in project
+ assert:
+ that:
+ - sshkey is successful
+
+- name: cleanup affinity group in project
+ cs_affinitygroup:
+ name: "{{ cs_resource_prefix }}-ag-prj"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: ag
+ until: ag is successful
+ retries: 20
+ delay: 5
+- name: verify cleanup affinity group in project
+ assert:
+ that:
+ - ag is successful
+
+- name: cleanup security group in project ...take a while unless instance in project is expunged
+ cs_securitygroup:
+ name: "{{ cs_resource_prefix }}-sg-prj"
+ project: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: sg
+ until: sg is successful
+ retries: 100
+ delay: 10
+- name: verify cleanup security group in project
+ assert:
+ that:
+ - sg is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/setup.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/setup.yml
new file mode 100644
index 00000000..6600f0f9
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/setup.yml
@@ -0,0 +1,27 @@
+---
+- name: setup ssh key
+ cs_sshkeypair:
+ name: "{{ cs_resource_prefix }}-sshkey"
+ register: sshkey
+- name: verify setup ssh key
+ assert:
+ that:
+ - sshkey is successful
+
+- name: setup affinity group
+ cs_affinitygroup:
+ name: "{{ cs_resource_prefix }}-ag"
+ register: ag
+- name: verify setup affinity group
+ assert:
+ that:
+ - ag is successful
+
+- name: setup security group
+ cs_securitygroup:
+ name: "{{ cs_resource_prefix }}-sg"
+ register: sg
+- name: verify setup security group
+ assert:
+ that:
+ - sg is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/sshkeys.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/sshkeys.yml
new file mode 100644
index 00000000..89202773
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/sshkeys.yml
@@ -0,0 +1,181 @@
+---
+- name: test update instance ssh key non existent
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey-does-not-exist"
+ template: "{{ test_cs_instance_template }}"
+ force: true
+ register: instance
+ ignore_errors: true
+- name: verify update instance ssh key non existent
+ assert:
+ that:
+ - instance is failed
+ - 'instance.msg == "SSH key not found: {{ cs_resource_prefix }}-sshkey-does-not-exist"'
+
+- name: test create instance without keypair in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ check_mode: true
+ register: instance
+- name: verify create instance without keypair in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+
+- name: test create instance without keypair
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ register: instance
+- name: verify create instance without keypair
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.ssh_key is not defined
+
+- name: test create instance without keypair idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ register: instance
+- name: verify create instance without keypair idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.ssh_key is not defined
+
+- name: setup ssh key2
+ cs_sshkeypair:
+ name: "{{ cs_resource_prefix }}-sshkey2"
+ register: sshkey
+- name: verify setup ssh key2
+ assert:
+ that:
+ - sshkey is successful
+
+- name: test update instance ssh key2 in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey2"
+ force: true
+ check_mode: true
+ register: instance
+- name: verify update instance ssh key2 in check mode
+ assert:
+ that:
+ - instance is changed
+ - instance.ssh_key is not defined
+
+- name: test update instance ssh key2
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey2"
+ force: true
+ register: instance
+- name: verify update instance ssh key2
+ assert:
+ that:
+ - instance is changed
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey2"
+
+- name: test update instance ssh key2 idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey2"
+ force: true
+ register: instance
+- name: verify update instance ssh key2 idempotence
+ assert:
+ that:
+ - instance is not changed
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey2"
+
+- name: cleanup ssh key2
+ cs_sshkeypair:
+ name: "{{ cs_resource_prefix }}-sshkey2"
+ state: absent
+ register: sshkey2
+- name: verify cleanup ssh key2
+ assert:
+ that:
+ - sshkey2 is successful
+
+- name: test update instance ssh key2 idempotence2
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey2"
+ force: true
+ register: instance
+ ignore_errors: true
+- name: verify update instance ssh key2 idempotence2
+ assert:
+ that:
+ - instance is failed
+ - 'instance.msg == "SSH key not found: {{ cs_resource_prefix }}-sshkey2"'
+
+- name: test update instance ssh key in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey"
+ force: true
+ check_mode: true
+ register: instance
+- name: verify update instance ssh key in check mode
+ assert:
+ that:
+ - instance is changed
+ - instance.ssh_key is not defined
+
+- name: test update instance ssh key
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey"
+ force: true
+ register: instance
+- name: verify update instance ssh key
+ assert:
+ that:
+ - instance is changed
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey"
+
+- name: test update instance ssh key idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey"
+ force: true
+ register: instance
+- name: verify update instance ssh key idempotence
+ assert:
+ that:
+ - instance is not changed
+ - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey"
+
+- name: cleanup expunge instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-sshkey"
+ zone: "{{ cs_common_zone_basic }}"
+ state: expunged
+ register: instance
+- name: verify cleanup expunge instance
+ assert:
+ that:
+ - instance is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/tags.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/tags.yml
new file mode 100644
index 00000000..667e5a8b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/tags.yml
@@ -0,0 +1,140 @@
+---
+- name: test add tags to instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ tags:
+ - { key: "{{ cs_resource_prefix }}-tag1", value: "{{ cs_resource_prefix }}-value1" }
+ - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" }
+ register: instance
+ check_mode: true
+- name: verify add tags to instance in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - not instance.tags
+
+- name: test add tags to instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ tags:
+ - { key: "{{ cs_resource_prefix }}-tag1", value: "{{ cs_resource_prefix }}-value1" }
+ - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" }
+ register: instance
+- name: verify add tags to instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.tags|length == 2
+ - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]"
+ - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]"
+ - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]"
+ - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]"
+
+- name: test tags to instance idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ tags:
+ - { key: "{{ cs_resource_prefix }}-tag1", value: "{{ cs_resource_prefix }}-value1" }
+ - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" }
+ register: instance
+- name: verify tags to instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.tags|length == 2
+ - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]"
+ - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]"
+ - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]"
+ - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]"
+
+- name: test change tags of instance in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ tags:
+ - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" }
+ - { key: "{{ cs_resource_prefix }}-tag3", value: "{{ cs_resource_prefix }}-value3" }
+ register: instance
+ check_mode: true
+- name: verify tags to instance idempotence in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.tags|length == 2
+ - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]"
+ - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]"
+ - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]"
+ - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]"
+
+- name: test change tags of instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ tags:
+ - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" }
+ - { key: "{{ cs_resource_prefix }}-tag3", value: "{{ cs_resource_prefix }}-value3" }
+ register: instance
+- name: verify tags to instance idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.tags|length == 2
+ - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag3' ]"
+ - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag3' ]"
+ - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value3' ]"
+ - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value3' ]"
+
+- name: test not touch tags of instance if no param tags
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ register: instance
+- name: verify not touch tags of instance if no param tags
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.tags|length == 2
+ - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag3' ]"
+ - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag3' ]"
+ - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value3' ]"
+ - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value3' ]"
+
+- name: test remove tags in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ tags: []
+ register: instance
+ check_mode: true
+- name: verify remove tags in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.tags|length != 0
+
+- name: test remove tags
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
+ zone: "{{ cs_common_zone_basic }}"
+ tags: []
+ register: instance
+- name: verify remove tags
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.tags|length == 0
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/defaults/main.yml
new file mode 100644
index 00000000..490c6c14
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+test_cs_instance_template: "{{ cs_common_template }}"
+test_cs_instance_offering_1: Small Instance
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/tasks/main.yml
new file mode 100644
index 00000000..c56caf5a
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/tasks/main.yml
@@ -0,0 +1,80 @@
+---
+- name: setup ssh key
+ cs_sshkeypair:
+ name: "{{ cs_resource_prefix }}-sshkey"
+ register: sshkey
+
+- name: setup affinity group
+ cs_affinitygroup:
+ name: "{{ cs_resource_prefix }}-ag"
+
+- name: setup security group
+ cs_securitygroup:
+ name: "{{ cs_resource_prefix }}-sg"
+
+- name: setup instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ affinity_group: "{{ cs_resource_prefix }}-ag"
+ security_group: "{{ cs_resource_prefix }}-sg"
+ ssh_key: "{{ cs_resource_prefix }}-sshkey"
+ tags: []
+ zone: "{{ cs_common_zone_basic }}"
+ register: instance
+ until: instance is successful
+ retries: 20
+ delay: 5
+
+- name: test instance info in check mode
+ cs_instance_info:
+ name: "{{ cs_resource_prefix }}-vm"
+ register: instance_info
+ check_mode: true
+- name: verify test instance info in check mode
+ assert:
+ that:
+ - instance_info is successful
+ - instance_info is not changed
+ - instance_info.instances[0].id == instance.id
+ - instance_info.instances[0].domain == instance.domain
+ - instance_info.instances[0].account == instance.account
+ - instance_info.instances[0].zone == instance.zone
+ - instance_info.instances[0].name == instance.name
+ - instance_info.instances[0].service_offering == instance.service_offering
+ - instance_info.instances[0].host != ""
+
+- name: test instance info
+ cs_instance_info:
+ name: "{{ cs_resource_prefix }}-vm"
+ register: instance_info
+- name: verify test instance info
+ assert:
+ that:
+ - instance_info is successful
+ - instance_info is not changed
+ - instance_info.instances[0].id == instance.id
+ - instance_info.instances[0].domain == instance.domain
+ - instance_info.instances[0].account == instance.account
+ - instance_info.instances[0].zone == instance.zone
+ - instance_info.instances[0].name == instance.name
+ - instance_info.instances[0].service_offering == instance.service_offering
+ - instance_info.instances[0].host != ""
+
+- name: test instance info for all instances
+ cs_instance_info:
+ register: instance_info
+- name: verify test instance info
+ assert:
+ that:
+ - instance_info is successful
+ - instance_info is not changed
+ - instance_info.instances | length > 0
+ - '"id" in instance_info.instances[0]'
+ - '"domain" in instance_info.instances[0]'
+ - '"account" in instance_info.instances[0]'
+ - '"zone" in instance_info.instances[0]'
+ - '"name" in instance_info.instances[0]'
+ - '"service_offering" in instance_info.instances[0]'
+ - '"host" in instance_info.instances[0]'
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/tasks/main.yml
new file mode 100644
index 00000000..83b564e1
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/tasks/main.yml
@@ -0,0 +1,306 @@
+---
+- name: setup network
+ cs_network:
+ name: "net_nic"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: DefaultSharedNetworkOffering
+ network_domain: example.com
+ vlan: 1234
+ start_ip: 10.100.123.11
+ end_ip: 10.100.123.250
+ gateway: 10.100.123.1
+ netmask: 255.255.255.0
+ register: net
+- name: verify setup network
+ assert:
+ that:
+ - net is successful
+ - net.name == "net_nic"
+
+- name: setup instance
+ cs_instance:
+ name: "instance-nic-vm"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ network: "net_nic"
+ state: stopped
+ register: instance
+- name: verify setup instance
+ assert:
+ that:
+ - instance is successful
+ - instance.name == "instance-nic-vm"
+ - instance.state == "Stopped"
+
+- name: setup network 2
+ cs_network:
+ name: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: DefaultSharedNetworkOffering
+ network_domain: example.com
+ vlan: 1235
+ start_ip: 10.100.124.11
+ end_ip: 10.100.124.250
+ gateway: 10.100.124.1
+ netmask: 255.255.255.0
+ register: net
+- name: verify setup network 2
+ assert:
+ that:
+ - net is successful
+ - net.name == "net_nic2"
+
+- name: setup absent nic
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: nic
+- name: verify setup absent nic
+ assert:
+ that:
+ - nic is successful
+
+- name: test fail missing params
+ cs_instance_nic:
+ ignore_errors: true
+ register: nic
+- name: verify test fail missing params
+ assert:
+ that:
+ - nic is failed
+ - "nic.msg.startswith('missing required arguments: ')"
+
+- name: test create nic in check mode
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ check_mode: yes
+ register: nic
+- name: verify test create nic in check mode
+ assert:
+ that:
+ - nic is successful
+ - nic is changed
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+
+- name: test create nic
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ ip_address: 10.100.124.42
+ zone: "{{ cs_common_zone_adv }}"
+ register: nic
+- name: verify test create nic
+ assert:
+ that:
+ - nic is successful
+ - nic is changed
+ - nic.ip_address == "10.100.124.42"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: test create nic idempotence
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ ip_address: 10.100.124.42
+ zone: "{{ cs_common_zone_adv }}"
+ register: nic
+- name: verify test create nic idempotence
+ assert:
+ that:
+ - nic is successful
+ - nic is not changed
+ - nic.ip_address == "10.100.124.42"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: test create nic without ip address idempotence
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ register: nic
+- name: verify test create nic without ip address idempotence
+ assert:
+ that:
+ - nic is successful
+ - nic is not changed
+ - nic.ip_address == "10.100.124.42"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: test update nic in check mode
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ ip_address: 10.100.124.23
+ zone: "{{ cs_common_zone_adv }}"
+ check_mode: yes
+ register: nic
+- name: verify test update nic in check mode
+ assert:
+ that:
+ - nic is successful
+ - nic is changed
+ - nic.ip_address == "10.100.124.42"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: test update nic
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ ip_address: 10.100.124.23
+ zone: "{{ cs_common_zone_adv }}"
+ register: nic
+- name: verify test update nic
+ assert:
+ that:
+ - nic is successful
+ - nic is changed
+ - nic.ip_address == "10.100.124.23"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: test update nic idempotence
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ ip_address: 10.100.124.23
+ zone: "{{ cs_common_zone_adv }}"
+ register: nic
+- name: verify test update nic idempotence
+ assert:
+ that:
+ - nic is successful
+ - nic is not changed
+ - nic.ip_address == "10.100.124.23"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: test update nic without ip address idempotence
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ register: nic
+- name: verify test update nic without ip address idempotence
+ assert:
+ that:
+ - nic is successful
+ - nic is not changed
+ - nic.ip_address == "10.100.124.23"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: test remove nic in check mode
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ check_mode: yes
+ register: nic
+- name: verify test remove nic in check mode
+ assert:
+ that:
+ - nic is successful
+ - nic is changed
+ - nic.ip_address == "10.100.124.23"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: test remove nic
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: nic
+- name: verify test remove nic
+ assert:
+ that:
+ - nic is successful
+ - nic is changed
+ - nic.ip_address == "10.100.124.23"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: test remove nic idempotence
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: nic
+- name: verify test remove nic idempotence
+ assert:
+ that:
+ - nic is successful
+ - nic is not changed
+
+- name: cleanup instance
+ cs_instance:
+ name: "instance-nic-vm"
+ state: expunged
+ register: instance
+- name: verify cleanup instance
+ assert:
+ that:
+ - instance is successful
+
+- name: cleanup network
+ cs_network:
+ name: "net_nic"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: net
+- name: verify cleanup network
+ assert:
+ that:
+ - net is successful
+
+- name: cleanup network 2
+ cs_network:
+ name: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: net
+- name: verify cleanup network 2
+ assert:
+ that:
+ - net is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/tasks/main.yml
new file mode 100644
index 00000000..22241e64
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/tasks/main.yml
@@ -0,0 +1,221 @@
+---
+- name: setup network
+ cs_network:
+ name: "net_nic"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: DefaultSharedNetworkOffering
+ network_domain: example.com
+ vlan: "1234"
+ start_ip: 10.100.123.11
+ end_ip: 10.100.123.250
+ gateway: 10.100.123.1
+ netmask: 255.255.255.0
+ register: net
+- name: verify setup network
+ assert:
+ that:
+ - net is successful
+ - net.name == "net_nic"
+
+- name: setup instance
+ cs_instance:
+ name: "instance-nic-vm"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ network: "net_nic"
+ state: stopped
+ register: instance
+- name: verify setup instance
+ assert:
+ that:
+ - instance is successful
+ - instance.name == "instance-nic-vm"
+ - instance.state == "Stopped"
+
+- name: setup network 2
+ cs_network:
+ name: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: DefaultSharedNetworkOffering
+ network_domain: example.com
+ vlan: "1235"
+ start_ip: 10.100.124.11
+ end_ip: 10.100.124.250
+ gateway: 10.100.124.1
+ netmask: 255.255.255.0
+ register: net
+- name: verify setup network 2
+ assert:
+ that:
+ - net is successful
+ - net.name == "net_nic2"
+
+- name: setup nic
+ cs_instance_nic:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ ip_address: 10.100.124.42
+ zone: "{{ cs_common_zone_adv }}"
+ register: nic
+- name: verify test create nic
+ assert:
+ that:
+ - nic is successful
+ - nic.ip_address == "10.100.124.42"
+ - nic.netmask == "255.255.255.0"
+ - nic.network == "net_nic2"
+ - nic.vm == "instance-nic-vm"
+ - nic.zone == "{{ cs_common_zone_adv }}"
+ - nic.mac_address is defined
+
+- name: setup remove secondary ip
+ cs_instance_nic_secondaryip:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ vm_guest_ip: 10.100.124.43
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sip
+- name: verify setup remove secondary ip
+ assert:
+ that:
+ - sip is successful
+
+- name: test add secondary ip in check mode
+ cs_instance_nic_secondaryip:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ vm_guest_ip: 10.100.124.43
+ zone: "{{ cs_common_zone_adv }}"
+ check_mode: true
+ register: sip
+- name: verify test add secondary ip in check mode
+ assert:
+ that:
+ - sip is successful
+ - sip is changed
+ - sip.network == "net_nic2"
+ - sip.vm == "instance-nic-vm"
+ - sip.zone == "{{ cs_common_zone_adv }}"
+
+- name: test add secondary ip
+ cs_instance_nic_secondaryip:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ vm_guest_ip: 10.100.124.43
+ zone: "{{ cs_common_zone_adv }}"
+ register: sip
+- name: verify test add secondary ip
+ assert:
+ that:
+ - sip is successful
+ - sip is changed
+ - sip.vm_guest_ip == "10.100.124.43"
+ - sip.network == "net_nic2"
+ - sip.vm == "instance-nic-vm"
+ - sip.zone == "{{ cs_common_zone_adv }}"
+
+- name: test add secondary ip idempotence
+ cs_instance_nic_secondaryip:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ vm_guest_ip: 10.100.124.43
+ zone: "{{ cs_common_zone_adv }}"
+ register: sip
+- name: verify test add secondary ip idempotence
+ assert:
+ that:
+ - sip is successful
+ - sip is not changed
+ - sip.vm_guest_ip == "10.100.124.43"
+ - sip.network == "net_nic2"
+ - sip.vm == "instance-nic-vm"
+ - sip.zone == "{{ cs_common_zone_adv }}"
+
+- name: test remove secondary ip in check mode
+ cs_instance_nic_secondaryip:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ vm_guest_ip: 10.100.124.43
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ check_mode: true
+ register: sip
+- name: verify test remove secondary ip in check mode
+ assert:
+ that:
+ - sip is successful
+ - sip is changed
+ - sip.vm_guest_ip == "10.100.124.43"
+ - sip.network == "net_nic2"
+ - sip.vm == "instance-nic-vm"
+ - sip.zone == "{{ cs_common_zone_adv }}"
+
+- name: test remove secondary ip
+ cs_instance_nic_secondaryip:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ vm_guest_ip: 10.100.124.43
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sip
+- name: verify test remove secondary ip
+ assert:
+ that:
+ - sip is successful
+ - sip is changed
+ - sip.vm_guest_ip == "10.100.124.43"
+ - sip.network == "net_nic2"
+ - sip.vm == "instance-nic-vm"
+ - sip.zone == "{{ cs_common_zone_adv }}"
+
+- name: test remove secondary ip idempotence
+ cs_instance_nic_secondaryip:
+ vm: "instance-nic-vm"
+ network: "net_nic2"
+ vm_guest_ip: 10.100.124.43
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sip
+- name: verify test remove secondary ip idempotence
+ assert:
+ that:
+ - sip is successful
+ - sip is not changed
+ - sip.network == "net_nic2"
+ - sip.vm == "instance-nic-vm"
+ - sip.zone == "{{ cs_common_zone_adv }}"
+
+- name: cleanup instance
+ cs_instance:
+ name: "instance-nic-vm"
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+ register: instance
+- name: verify cleanup instance
+ assert:
+ that:
+ - instance is successful
+
+- name: cleanup network
+ cs_network:
+ name: "net_nic"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: net
+- name: verify cleanup network
+ assert:
+ that:
+ - net is successful
+
+- name: cleanup network 2
+ cs_network:
+ name: "net_nic2"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: net
+- name: verify cleanup network 2
+ assert:
+ that:
+ - net is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/tasks/main.yml
new file mode 100644
index 00000000..8a9155b0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/tasks/main.yml
@@ -0,0 +1,94 @@
+---
+- name: reset without giving a VM
+ action: cs_instance_password_reset
+ ignore_errors: yes
+ register: reset1
+- name: verify that the argument was missing
+ assert:
+ that:
+ - reset1 is failed
+ - "reset1.msg == 'missing required arguments: vm'"
+
+- name: disable password_enabled on default template
+ cs_template:
+ name: "{{ cs_common_template }}"
+ template_filter: all
+ password_enabled: no
+ zone: "{{ cs_common_zone_adv }}"
+
+- name: cleanup test VM
+ cs_instance:
+ name: test-nopassword
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+
+- name: create test VM
+ cs_instance:
+ name: test-nopassword
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: started
+ register: testvm_nopass
+ until: testvm_nopass is success
+ retries: 12
+ delay: 10
+
+- name: stop test VM
+ cs_instance:
+ name: test-nopassword
+ zone: "{{ cs_common_zone_adv }}"
+ state: stopped
+
+- name: reset nopassword
+ cs_instance_password_reset:
+ vm: test-nopassword
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: yes
+ register: reset2
+- name: verify that template was not pw enabled
+ assert:
+ that:
+ - reset2 is failed
+ - reset2.msg.endswith("the template is not password enabled'")
+
+- name: enable password_enabled on default template
+ cs_template:
+ name: "{{ cs_common_template }}"
+ template_filter: all
+ password_enabled: yes
+ zone: "{{ cs_common_zone_adv }}"
+
+- name: cleanup test VM
+ cs_instance:
+ name: test-password
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+
+- name: create test VM
+ cs_instance:
+ name: test-password
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: started
+
+- name: stop test VM
+ cs_instance:
+ name: test-password
+ zone: "{{ cs_common_zone_adv }}"
+ state: stopped
+
+- name: reset password
+ cs_instance_password_reset:
+ vm: test-password
+ zone: "{{ cs_common_zone_adv }}"
+ register: reset3
+- name: verify that a password was set
+ assert:
+ that:
+ - reset3 is success
+ - reset3.password != ''
+
+- debug:
+ var: reset3.password
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/tasks/main.yml
new file mode 100644
index 00000000..6ba31751
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/tasks/main.yml
@@ -0,0 +1,79 @@
+---
+- name: setup
+ cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent
+ register: ig
+- name: verify setup
+ assert:
+ that:
+ - ig is successful
+
+- name: test fail if missing name
+ action: cs_instancegroup
+ register: ig
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - ig is failed
+ - "ig.msg == 'missing required arguments: name'"
+
+- name: test present instance group in check mode
+ cs_instancegroup: name={{ cs_resource_prefix }}_ig
+ register: ig
+ check_mode: true
+- name: verify results of create instance group in check mode
+ assert:
+ that:
+ - ig is successful
+ - ig is changed
+
+- name: test present instance group
+ cs_instancegroup: name={{ cs_resource_prefix }}_ig
+ register: ig
+- name: verify results of create instance group
+ assert:
+ that:
+ - ig is successful
+ - ig is changed
+ - ig.name == "{{ cs_resource_prefix }}_ig"
+
+- name: test present instance group is idempotence
+ cs_instancegroup: name={{ cs_resource_prefix }}_ig
+ register: ig
+- name: verify results present instance group is idempotence
+ assert:
+ that:
+ - ig is successful
+ - ig is not changed
+ - ig.name == "{{ cs_resource_prefix }}_ig"
+
+- name: test absent instance group in check mode
+ cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent
+ register: ig
+ check_mode: true
+- name: verify results of absent instance group in check mode
+ assert:
+ that:
+ - ig is successful
+ - ig is changed
+ - ig.name == "{{ cs_resource_prefix }}_ig"
+
+- name: test absent instance group
+ cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent
+ register: ig
+- name: verify results of absent instance group
+ assert:
+ that:
+ - ig is successful
+ - ig is changed
+ - ig.name == "{{ cs_resource_prefix }}_ig"
+
+- name: test absent instance group is idempotence
+ cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent
+ register: ig
+- name: verify results of absent instance group is idempotence
+ assert:
+ that:
+ - ig is successful
+ - ig is not changed
+ - ig.name is undefined
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/main.yml
new file mode 100644
index 00000000..48ccd023
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/main.yml
@@ -0,0 +1,19 @@
+---
+- name: test fail vpc and network mutually exclusive
+ cs_ip_address:
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ vpc: "foobar"
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: yes
+ register: ip_address
+- name: verify test fail vpc and network mutually exclusive
+ assert:
+ that:
+ - ip_address is failed
+ - 'ip_address.msg == "parameters are mutually exclusive: vpc|network"'
+
+- name: run test for network setup
+ import_tasks: network.yml
+
+- name: run test for vpc setup
+ import_tasks: vpc.yml
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/network.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/network.yml
new file mode 100644
index 00000000..e87ff972
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/network.yml
@@ -0,0 +1,240 @@
+---
+- name: setup ensure the test network is absent
+ cs_network:
+ name: ipaddr_test_network
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+
+- name: setup create the test network
+ cs_network:
+ name: ipaddr_test_network
+ network_offering: DefaultIsolatedNetworkOfferingWithSourceNatService
+ state: present
+ zone: "{{ cs_common_zone_adv }}"
+ register: base_network
+- name: setup verify create the test network
+ assert:
+ that:
+ - base_network is successful
+
+- name: setup instance to get network in implementation state
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-cs-ip-address"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ networks:
+ - "{{ base_network.name }}"
+ register: instance
+ until: instance is success
+ retries: 20
+ delay: 5
+- name: verify instance setup
+ assert:
+ that:
+ - instance is successful
+
+- name: setup clean ip_address with tags
+ cs_ip_address:
+ state: absent
+ tags:
+ - key: unique_id
+ value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861"
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+
+- name: setup associate ip_address for SNAT
+ cs_ip_address:
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address_snat
+
+- name: test associate ip_address in check mode
+ cs_ip_address:
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ check_mode: true
+ register: ip_address
+- name: verify test associate ip_address in check mode
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is changed
+
+- name: test associate ip_address
+ cs_ip_address:
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify test associate ip_address
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is changed
+ - ip_address.ip_address is defined
+
+- name: test associate ip_address with tags in check mode
+ cs_ip_address:
+ network: ipaddr_test_network
+ tags:
+ - key: unique_id
+ value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address_tag
+ check_mode: true
+- name: verify test associate ip_address with tags in check mode
+ assert:
+ that:
+ - ip_address_tag is successful
+ - ip_address_tag is changed
+
+- name: test associate ip_address with tags
+ cs_ip_address:
+ network: ipaddr_test_network
+ tags:
+ - key: unique_id
+ value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address_tag
+- name: verify test associate ip_address with tags
+ assert:
+ that:
+ - ip_address_tag is successful
+ - ip_address_tag is changed
+ - ip_address_tag.ip_address is defined
+ - ip_address_tag.tags.0.key == "unique_id"
+ - ip_address_tag.tags.0.value == "adacd65e-7868-5ebf-9f8b-e6e0ea779861"
+
+- name: test associate ip_address with tags idempotence
+ cs_ip_address:
+ network: ipaddr_test_network
+ tags:
+ - key: unique_id
+ value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address_tag
+- name: verify test associate ip_address with tags idempotence
+ assert:
+ that:
+ - ip_address_tag is successful
+ - ip_address_tag is not changed
+ - ip_address_tag.ip_address is defined
+ - ip_address_tag.state == "Allocated"
+ - ip_address_tag.tags.0.key == "unique_id"
+ - ip_address_tag.tags.0.value == "adacd65e-7868-5ebf-9f8b-e6e0ea779861"
+
+- name: test disassiociate ip_address with missing param ip_address
+ cs_ip_address:
+ state: absent
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: true
+ register: ip_address_err
+- name: verify test disassiociate ip_address with missing param ip_address
+ assert:
+ that:
+ - ip_address_err is failed
+ - 'ip_address_err.msg == "state is absent but any of the following are missing: ip_address, tags"'
+
+- name: test disassociate ip_address in check mode
+ cs_ip_address:
+ state: absent
+ ip_address: "{{ ip_address.ip_address }}"
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ check_mode: true
+ register: ip_address
+- name: verify test disassociate ip_address in check mode
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is changed
+
+- name: test disassociate ip_address
+ cs_ip_address:
+ state: absent
+ ip_address: "{{ ip_address.ip_address }}"
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify test disassociate ip_address
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is changed
+
+- name: test disassociate ip_address idempotence
+ cs_ip_address:
+ state: absent
+ ip_address: "{{ ip_address.ip_address }}"
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify test disassociate ip_address idempotence
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is not changed
+
+- name: test disassociate ip_address with tags with check mode
+ cs_ip_address:
+ state: absent
+ tags:
+ - key: unique_id
+ value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861"
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ check_mode: true
+ register: ip_address
+- name: verify test disassociate ip_address with tags in check mode
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is changed
+
+- name: test disassociate ip_address with tags
+ cs_ip_address:
+ state: absent
+ tags:
+ - key: unique_id
+ value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861"
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify test disassociate ip_address with tags
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is changed
+
+- name: test disassociate ip_address with tags idempotence
+ cs_ip_address:
+ state: absent
+ tags:
+ - key: unique_id
+ value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861"
+ network: ipaddr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify test disassociate ip_address with tags idempotence
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is not changed
+
+- name: cleanup instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-cs-ip-address"
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+ register: instance
+- name: verify instance cleanup
+ assert:
+ that:
+ - instance is successful
+
+- name: clean the test network
+ cs_network:
+ name: ipaddr_test_network
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/vpc.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/vpc.yml
new file mode 100644
index 00000000..3a089ebd
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/vpc.yml
@@ -0,0 +1,121 @@
+---
+- name: setup vpc
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc_ip_address"
+ cidr: 10.10.111.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify setup vpc
+ assert:
+ that:
+ - vpc is successful
+
+- name: setup clean ip_address with tags
+ cs_ip_address:
+ state: absent
+ vpc: "{{ cs_resource_prefix }}_vpc_ip_address"
+ tags:
+ - key: unique_id
+ value: "86cdce4c-dce7-11e8-8394-00262df3bf70"
+ zone: "{{ cs_common_zone_adv }}"
+
+- name: test associate ip_address in vpc with tags in check mode
+ cs_ip_address:
+ vpc: "{{ cs_resource_prefix }}_vpc_ip_address"
+ tags:
+ - key: unique_id
+ value: "86cdce4c-dce7-11e8-8394-00262df3bf70"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address_tag
+ check_mode: yes
+- name: verify test associate ip_address in vpc with tags in check mode
+ assert:
+ that:
+ - ip_address_tag is successful
+ - ip_address_tag is changed
+
+- name: test associate ip_address in vpc with tags
+ cs_ip_address:
+ vpc: "{{ cs_resource_prefix }}_vpc_ip_address"
+ tags:
+ - key: unique_id
+ value: "86cdce4c-dce7-11e8-8394-00262df3bf70"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address_tag
+- name: verify test associate ip_address in vpc with tags
+ assert:
+ that:
+ - ip_address_tag is successful
+ - ip_address_tag is changed
+ - ip_address_tag.ip_address is defined
+ - ip_address_tag.tags.0.key == "unique_id"
+ - ip_address_tag.tags.0.value == "86cdce4c-dce7-11e8-8394-00262df3bf70"
+
+- name: test associate ip_address in vpc with tags idempotence
+ cs_ip_address:
+ vpc: "{{ cs_resource_prefix }}_vpc_ip_address"
+ tags:
+ - key: unique_id
+ value: "86cdce4c-dce7-11e8-8394-00262df3bf70"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address_tag
+- name: verify test associate ip_address in vpc with tags idempotence
+ assert:
+ that:
+ - ip_address_tag is successful
+ - ip_address_tag is not changed
+ - ip_address_tag.ip_address is defined
+ - ip_address_tag.state == "Allocated"
+ - ip_address_tag.tags.0.key == "unique_id"
+ - ip_address_tag.tags.0.value == "86cdce4c-dce7-11e8-8394-00262df3bf70"
+
+- name: test disassociate ip_address in vpc in check mode
+ cs_ip_address:
+ state: absent
+ ip_address: "{{ ip_address_tag.ip_address }}"
+ vpc: "{{ cs_resource_prefix }}_vpc_ip_address"
+ zone: "{{ cs_common_zone_adv }}"
+ check_mode: true
+ register: ip_address
+- name: verify test disassociate ip_address in vpc in check mode
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is changed
+
+- name: test disassociate ip_address in vpc
+ cs_ip_address:
+ state: absent
+ ip_address: "{{ ip_address_tag.ip_address }}"
+ vpc: "{{ cs_resource_prefix }}_vpc_ip_address"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify test disassociate ip_address in vpc
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is changed
+
+- name: test disassociate ip_address in vpc idempotence
+ cs_ip_address:
+ state: absent
+ ip_address: "{{ ip_address_tag.ip_address }}"
+ vpc: "{{ cs_resource_prefix }}_vpc_ip_address"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify test disassociate ip_address in vpc idempotence
+ assert:
+ that:
+ - ip_address is successful
+ - ip_address is not changed
+
+- name: cleanup vpc
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc_ip_address"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpc
+- name: verify cleanup vpc
+ assert:
+ that:
+ - vpc is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/tasks/main.yml
new file mode 100644
index 00000000..de279224
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/tasks/main.yml
@@ -0,0 +1,143 @@
+---
+- name: setup iso
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ cross_zones: true
+ state: absent
+ register: iso
+- name: verify setup iso
+ assert:
+ that:
+ - iso is successful
+
+- name: test download iso in check mode
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ url: "{{ cs_iso_url }}"
+ os_type: Debian GNU/Linux 7(64-bit)
+ cross_zones: true
+ register: iso
+ check_mode: true
+- name: verify test download iso in check mode
+ assert:
+ that:
+ - iso is changed
+
+- name: test download iso
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ url: "{{ cs_iso_url }}"
+ os_type: Debian GNU/Linux 7(64-bit)
+ cross_zones: true
+ register: iso
+- name: verify test download iso
+ assert:
+ that:
+ - iso is changed
+ - iso.name == "{{ cs_resource_prefix }}-iso"
+ - iso.display_text == "{{ cs_resource_prefix }}-iso"
+ - iso.cross_zones == true
+
+- name: test download iso idempotence
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ url: "{{ cs_iso_url }}"
+ os_type: Debian GNU/Linux 7(64-bit)
+ cross_zones: true
+ register: iso
+- name: verify test download iso idempotence
+ assert:
+ that:
+ - iso is not changed
+ - iso.name == "{{ cs_resource_prefix }}-iso"
+ - iso.display_text == "{{ cs_resource_prefix }}-iso"
+ - iso.cross_zones == true
+
+- name: test update iso in check mdoe
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ display_text: "{{ cs_resource_prefix }}-iso display_text"
+ url: "{{ cs_iso_url }}"
+ os_type: CentOS 7
+ cross_zones: true
+ register: iso
+ check_mode: true
+- name: verify test update iso in check mode
+ assert:
+ that:
+ - iso is changed
+ - iso.name == "{{ cs_resource_prefix }}-iso"
+ - iso.display_text == "{{ cs_resource_prefix }}-iso"
+ - iso.cross_zones == true
+
+- name: test update iso
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ display_text: "{{ cs_resource_prefix }}-iso display_text"
+ url: "{{ cs_iso_url }}"
+ os_type: CentOS 7
+ cross_zones: true
+ register: iso
+- name: verify test update iso
+ assert:
+ that:
+ - iso is changed
+ - iso.name == "{{ cs_resource_prefix }}-iso"
+ - iso.display_text == "{{ cs_resource_prefix }}-iso display_text"
+ - iso.cross_zones == true
+
+- name: test update iso idempotence
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ display_text: "{{ cs_resource_prefix }}-iso display_text"
+ url: "{{ cs_iso_url }}"
+ os_type: CentOS 7
+ cross_zones: true
+ register: iso
+- name: verify test update iso idempotence
+ assert:
+ that:
+ - iso is not changed
+ - iso.name == "{{ cs_resource_prefix }}-iso"
+ - iso.display_text == "{{ cs_resource_prefix }}-iso display_text"
+ - iso.cross_zones == true
+
+- name: test remove iso in check mode
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ state: absent
+ cross_zones: true
+ register: iso
+ check_mode: true
+- name: verify test remove iso in check mode
+ assert:
+ that:
+ - iso is changed
+ - iso.name == "{{ cs_resource_prefix }}-iso"
+ - iso.display_text == "{{ cs_resource_prefix }}-iso display_text"
+ - iso.cross_zones == true
+
+- name: test remove iso
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ state: absent
+ cross_zones: true
+ register: iso
+- name: verify test remove iso
+ assert:
+ that:
+ - iso is changed
+ - iso.name == "{{ cs_resource_prefix }}-iso"
+ - iso.display_text == "{{ cs_resource_prefix }}-iso display_text"
+ - iso.cross_zones == true
+
+- name: test remove iso idempotence
+ cs_iso:
+ name: "{{ cs_resource_prefix }}-iso"
+ state: absent
+ cross_zones: true
+ register: iso
+- name: verify test remove iso idempotence
+ assert:
+ that:
+ - iso is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/vars/main b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/vars/main
new file mode 100644
index 00000000..1670b14c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/vars/main
@@ -0,0 +1,2 @@
+---
+cs_iso_url: https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-10.6.0-amd64-netinst.iso
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/tasks/main.yml
new file mode 100644
index 00000000..13d2f005
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/tasks/main.yml
@@ -0,0 +1,392 @@
+---
+- name: ensure instance is expunged
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-lb"
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+ register: instance
+- name: verify ensure instance is expunged
+ assert:
+ that:
+ - instance is successful
+
+- name: ensure network is absent
+ cs_network:
+ name: "{{ cs_resource_prefix }}_net_lb"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: lb_net
+- name: verify ensure network is absent
+ assert:
+ that:
+ - lb_net is successful
+
+- name: test create network for lb
+ cs_network:
+ name: "{{ cs_resource_prefix }}_net_lb"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: Offering for Isolated networks with Source Nat service enabled
+ register: lb_net
+- name: verify test create network for lb
+ assert:
+ that:
+ - lb_net is successful
+ - lb_net is changed
+ - lb_net.name == "{{ cs_resource_prefix }}_net_lb"
+
+- name: setup instance in lb
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-lb"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ network: "{{ cs_resource_prefix }}_net_lb"
+ register: instance
+ until: instance is success
+ retries: 20
+ delay: 5
+- name: verify setup instance in lb
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-lb"
+ - instance.state == "Running"
+
+- name: setup get ip address for lb
+ cs_ip_address:
+ network: "{{ cs_resource_prefix }}_net_lb"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify setup get ip address in lb
+ assert:
+ that:
+ - ip_address is successful
+
+- name: setup lb rule absent
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ state: absent
+ register: lb
+- name: verify setup lb rule absent
+ assert:
+ that:
+ - lb is successful
+
+- name: test rule requires params
+ cs_loadbalancer_rule:
+ ignore_errors: true
+ register: lb
+- name: verify test rule requires params
+ assert:
+ that:
+ - lb is failed
+ - "lb.msg.startswith('missing required arguments: ')"
+
+
+- name: test create rule in check mode
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ algorithm: roundrobin
+ public_port: 80
+ private_port: 8080
+ register: lb
+ check_mode: true
+- name: verify test create rule in check mode
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+
+- name: test create rule
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ algorithm: roundrobin
+ public_port: 80
+ private_port: 8080
+ register: lb
+- name: verify test create rule
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "roundrobin"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+
+- name: test create rule idempotence
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ algorithm: roundrobin
+ public_port: 80
+ private_port: 8080
+ register: lb
+- name: verify test create rule idempotence
+ assert:
+ that:
+ - lb is successful
+ - lb is not changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "roundrobin"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+
+- name: test update rule in check mode
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ algorithm: source
+ public_port: 80
+ private_port: 8080
+ register: lb
+ check_mode: true
+- name: verify test update rule in check mode
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "roundrobin"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+
+- name: test update rule
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ algorithm: source
+ public_port: 80
+ private_port: 8080
+ register: lb
+- name: verify test update rule
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "source"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+
+- name: test update rule idempotence
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ algorithm: source
+ public_port: 80
+ private_port: 8080
+ register: lb
+- name: verify test update rule idempotence
+ assert:
+ that:
+ - lb is successful
+ - lb is not changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "source"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+
+- name: test rule member requires params
+ cs_loadbalancer_rule_member:
+ ignore_errors: true
+ register: lb
+- name: verify test rule requires params
+ assert:
+ that:
+ - lb is failed
+ - "lb.msg.startswith('missing required arguments: ')"
+
+- name: test add members to rule in check mode
+ cs_loadbalancer_rule_member:
+ name: "{{ cs_resource_prefix }}_lb"
+ vm: "{{ cs_resource_prefix }}-vm-lb"
+ register: lb
+ check_mode: true
+- name: verify add members to rule in check mode
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "source"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+ - "'{{ cs_resource_prefix }}-vm-lb' not in lb.vms"
+
+- name: test add members to rule
+ cs_loadbalancer_rule_member:
+ name: "{{ cs_resource_prefix }}_lb"
+ vm: "{{ cs_resource_prefix }}-vm-lb"
+ register: lb
+- name: verify add members to rule
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "source"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+ - "'{{ cs_resource_prefix }}-vm-lb' in lb.vms"
+
+- name: test add members to rule idempotence
+ cs_loadbalancer_rule_member:
+ name: "{{ cs_resource_prefix }}_lb"
+ vm: "{{ cs_resource_prefix }}-vm-lb"
+ register: lb
+- name: verify add members to rule idempotence
+ assert:
+ that:
+ - lb is successful
+ - lb is not changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "source"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+ - "'{{ cs_resource_prefix }}-vm-lb' in lb.vms"
+
+- name: test remove members to rule in check mode
+ cs_loadbalancer_rule_member:
+ name: "{{ cs_resource_prefix }}_lb"
+ vm: "{{ cs_resource_prefix }}-vm-lb"
+ state: absent
+ register: lb
+ check_mode: true
+- name: verify remove members to rule in check mode
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "source"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+ - "'{{ cs_resource_prefix }}-vm-lb' in lb.vms"
+
+- name: test remove members to rule
+ cs_loadbalancer_rule_member:
+ name: "{{ cs_resource_prefix }}_lb"
+ vm: "{{ cs_resource_prefix }}-vm-lb"
+ state: absent
+ register: lb
+- name: verify remove members to rule
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "source"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+ - "'{{ cs_resource_prefix }}-vm-lb' not in lb.vms"
+
+- name: test remove members to rule idempotence
+ cs_loadbalancer_rule_member:
+ name: "{{ cs_resource_prefix }}_lb"
+ vm: "{{ cs_resource_prefix }}-vm-lb"
+ state: absent
+ register: lb
+- name: verify remove members to rule
+ assert:
+ that:
+ - lb is successful
+ - lb is not changed
+
+- name: test remove rule in check mode
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ state: absent
+ register: lb
+ check_mode: true
+- name: verify remove rule in check mode
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "source"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+
+- name: test remove rule
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ state: absent
+ register: lb
+- name: verify remove rule
+ assert:
+ that:
+ - lb is successful
+ - lb is changed
+ - lb.name == "{{ cs_resource_prefix }}_lb"
+ - lb.algorithm == "source"
+ - lb.public_ip == "{{ ip_address.ip_address }}"
+ - lb.public_port == 80
+ - lb.private_port == 8080
+
+- name: test remove rule idempotence
+ cs_loadbalancer_rule:
+ name: "{{ cs_resource_prefix }}_lb"
+ public_ip: "{{ ip_address.ip_address }}"
+ state: absent
+ register: lb
+- name: verify remove rule idempotence
+ assert:
+ that:
+ - lb is successful
+ - lb is not changed
+
+- name: cleanup ip address
+ cs_ip_address:
+ network: "{{ cs_resource_prefix }}_net_lb"
+ zone: "{{ cs_common_zone_adv }}"
+ ip_address: "{{ ip_address.ip_address }}"
+ state: absent
+ register: ip_address
+- name: verify cleanup ip address
+ assert:
+ that:
+ - ip_address is successful
+ - instance is changed
+
+- name: cleanup instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-lb"
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+ register: instance
+- name: verify cleanup instance
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+
+- name: cleanup network
+ cs_network:
+ name: "{{ cs_resource_prefix }}_net_lb"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: lb_net
+- name: verify cleanup network
+ assert:
+ that:
+ - lb_net is successful
+ - lb_net is changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/main.yml
new file mode 100644
index 00000000..cfe24c41
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+
+- include_tasks: vpc_network_tier.yml
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/vpc_network_tier.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/vpc_network_tier.yml
new file mode 100644
index 00000000..4854cae9
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/vpc_network_tier.yml
@@ -0,0 +1,299 @@
+---
+- name: setup cleanup vpc network tier
+ cs_network:
+ name: vpc tier 1
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: vpc_network_test
+ state: absent
+ ignore_errors: yes
+
+- name: setup cleanup existing vpc
+ cs_vpc:
+ name: vpc_network_test
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpc
+- name: verify cleanup existing vpc
+ assert:
+ that:
+ - vpc is successful
+
+- name: setup vpc
+ cs_vpc:
+ name: vpc_network_test
+ cidr: 10.43.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ vpc_offering: Redundant VPC offering
+ network_domain: cs2sandbox.simulator.example.com
+ register: vpc
+- name: verify setup vpc
+ assert:
+ that:
+ - vpc is successful
+
+- name: setup network acl
+ cs_network_acl:
+ name: my_network_acl1
+ vpc: vpc_network_test
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl
+- name: verify setup network acl
+ assert:
+ that:
+ - acl is successful
+
+- name: setup network acl rule
+ cs_network_acl_rule:
+ network_acl: my_network_acl1
+ rule_position: 1
+ vpc: vpc_network_test
+ traffic_type: ingress
+ action_policy: allow
+ port: 80
+ cidr: 0.0.0.0/0
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+- name: verify setup network acl rule
+ assert:
+ that:
+ - acl_rule is successful
+
+- name: setup vpc network tier
+ cs_network:
+ name: vpc tier 1
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: vpc_network_test
+ state: absent
+ register: network
+- name: verify setup vpc network tier
+ assert:
+ that:
+ - network is successful
+
+- name: test fail vpc network tier if vpc not given
+ cs_network:
+ name: vpc tier 1
+ zone: "{{ cs_common_zone_adv }}"
+ network_domain: cs2sandbox.simulator.example.com
+ network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks
+ gateway: 10.43.0.1
+ netmask: 255.255.255.0
+ acl: my_network_acl1
+ check_mode: yes
+ register: network
+ ignore_errors: yes
+- name: verify test fail vpc network tier if vpc not given
+ assert:
+ that:
+ - network is failed
+ - "network.msg == 'Missing required params: vpc'"
+
+- name: test create a vpc network tier in check mode
+ cs_network:
+ name: vpc tier 1
+ zone: "{{ cs_common_zone_adv }}"
+ network_domain: cs2sandbox.simulator.example.com
+ vpc: vpc_network_test
+ network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks
+ gateway: 10.43.0.1
+ netmask: 255.255.255.0
+ check_mode: yes
+ register: network
+- name: verify test create a vpc network tier in check mode
+ assert:
+ that:
+ - network is changed
+
+- name: test create a vpc network tier
+ cs_network:
+ name: vpc tier 1
+ zone: "{{ cs_common_zone_adv }}"
+ network_domain: cs2sandbox.simulator.example.com
+ vpc: vpc_network_test
+ network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks
+ gateway: 10.43.0.1
+ netmask: 255.255.255.0
+ register: network
+- name: verify test create a vpc network tier
+ assert:
+ that:
+ - network is changed
+ - network.acl_type == 'Account'
+ - not network.acl
+ - network.broadcast_domain_type == 'Vlan'
+ - network.cidr == '10.43.0.0/24'
+ - network.gateway == '10.43.0.1'
+ - network.display_text == 'vpc tier 1'
+ - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks'
+ - network.vpc == 'vpc_network_test'
+ - network.network_domain == 'cs2sandbox.simulator.example.com'
+
+- name: test create a vpc network tier idempotence
+ cs_network:
+ name: vpc tier 1
+ zone: "{{ cs_common_zone_adv }}"
+ network_domain: cs2sandbox.simulator.example.com
+ vpc: vpc_network_test
+ network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks
+ gateway: 10.43.0.1
+ netmask: 255.255.255.0
+ register: network
+- name: verify test create a vpc network tier idempotence
+ assert:
+ that:
+ - network is not changed
+ - network.acl_type == 'Account'
+ - not network.acl
+ - network.broadcast_domain_type == 'Vlan'
+ - network.cidr == '10.43.0.0/24'
+ - network.gateway == '10.43.0.1'
+ - network.display_text == 'vpc tier 1'
+ - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks'
+ - network.vpc == 'vpc_network_test'
+ - network.network_domain == 'cs2sandbox.simulator.example.com'
+
+- name: test update a vpc network tier in check mode
+ cs_network:
+ name: vpc tier 1
+ display_text: vpc tier 1 description
+ zone: "{{ cs_common_zone_adv }}"
+ network_domain: cs2sandbox.simulator.example.com
+ vpc: vpc_network_test
+ network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks
+ gateway: 10.43.0.1
+ netmask: 255.255.255.0
+ acl: my_network_acl1
+ check_mode: yes
+ register: network
+- name: verify test update a vpc network tier in check mode
+ assert:
+ that:
+ - network is changed
+ - network.acl_type == 'Account'
+ - network.acl == 'my_network_acl1'
+ - network.broadcast_domain_type == 'Vlan'
+ - network.cidr == '10.43.0.0/24'
+ - network.gateway == '10.43.0.1'
+ - network.display_text == 'vpc tier 1'
+ - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks'
+ - network.vpc == 'vpc_network_test'
+ - network.network_domain == 'cs2sandbox.simulator.example.com'
+
+- name: test update a vpc network tier
+ cs_network:
+ name: vpc tier 1
+ display_text: vpc tier 1 description
+ zone: "{{ cs_common_zone_adv }}"
+ network_domain: cs2sandbox.simulator.example.com
+ vpc: vpc_network_test
+ network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks
+ gateway: 10.43.0.1
+ netmask: 255.255.255.0
+ acl: my_network_acl1
+ register: network
+- name: verify test update a vpc network tier
+ assert:
+ that:
+ - network is changed
+ - network.acl_type == 'Account'
+ - network.acl == 'my_network_acl1'
+ - network.broadcast_domain_type == 'Vlan'
+ - network.cidr == '10.43.0.0/24'
+ - network.gateway == '10.43.0.1'
+ - network.display_text == 'vpc tier 1 description'
+ - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks'
+ - network.vpc == 'vpc_network_test'
+ - network.network_domain == 'cs2sandbox.simulator.example.com'
+
+- name: test update a vpc network tier idempotence
+ cs_network:
+ name: vpc tier 1
+ display_text: vpc tier 1 description
+ zone: "{{ cs_common_zone_adv }}"
+ network_domain: cs2sandbox.simulator.example.com
+ vpc: vpc_network_test
+ network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks
+ gateway: 10.43.0.1
+ netmask: 255.255.255.0
+ acl: my_network_acl1
+ register: network
+- name: verify test update a vpc network tier idempotence
+ assert:
+ that:
+ - network is not changed
+ - network.acl_type == 'Account'
+ - network.acl == 'my_network_acl1'
+ - network.broadcast_domain_type == 'Vlan'
+ - network.cidr == '10.43.0.0/24'
+ - network.gateway == '10.43.0.1'
+ - network.display_text == 'vpc tier 1 description'
+ - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks'
+ - network.vpc == 'vpc_network_test'
+ - network.network_domain == 'cs2sandbox.simulator.example.com'
+
+- name: test absent a vpc network tier in check mode
+ cs_network:
+ name: vpc tier 1
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: vpc_network_test
+ state: absent
+ register: network
+ check_mode: yes
+- name: verify test absent a vpc network tier in check mode
+ assert:
+ that:
+ - network is changed
+ - network.acl_type == 'Account'
+ - network.acl == 'my_network_acl1'
+ - network.broadcast_domain_type == 'Vlan'
+ - network.cidr == '10.43.0.0/24'
+ - network.gateway == '10.43.0.1'
+ - network.display_text == 'vpc tier 1 description'
+ - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks'
+ - network.vpc == 'vpc_network_test'
+ - network.network_domain == 'cs2sandbox.simulator.example.com'
+
+- name: test absent a vpc network tier
+ cs_network:
+ name: vpc tier 1
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: vpc_network_test
+ state: absent
+ register: network
+- name: verify test absent a vpc network tier
+ assert:
+ that:
+ - network is changed
+ - network.acl_type == 'Account'
+ - network.acl == 'my_network_acl1'
+ - network.broadcast_domain_type == 'Vlan'
+ - network.cidr == '10.43.0.0/24'
+ - network.gateway == '10.43.0.1'
+ - network.display_text == 'vpc tier 1 description'
+ - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks'
+ - network.vpc == 'vpc_network_test'
+ - network.network_domain == 'cs2sandbox.simulator.example.com'
+
+- name: test absent a vpc network tier idempotence
+ cs_network:
+ name: vpc tier 1
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: vpc_network_test
+ state: absent
+ register: network
+- name: verify test absent a vpc network tier idempotence
+ assert:
+ that:
+ - network is not changed
+
+- name: cleanup vpc
+ cs_vpc:
+ name: vpc_network_test
+ cidr: 10.43.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpc
+- name: verify cleanup vpc
+ assert:
+ that:
+ - vpc is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/tasks/main.yml
new file mode 100644
index 00000000..7104a7cb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/tasks/main.yml
@@ -0,0 +1,120 @@
+---
+- name: setup vpc
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text"
+ cidr: 10.10.0.0/16
+ vpc_offering: Redundant VPC offering
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify setup vpc
+ assert:
+ that:
+ - vpc is successful
+
+- name: setup network acl absent
+ cs_network_acl:
+ name: "{{ cs_resource_prefix }}_acl"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: acl
+- name: verify setup network acl absent
+ assert:
+ that:
+ - acl is successful
+
+- name: test fail missing param name and vpc for network acl
+ cs_network_acl:
+ ignore_errors: true
+ register: acl
+- name: verify test fail missing param name and vpc for network acl
+ assert:
+ that:
+ - acl is failed
+ - "acl.msg.startswith('missing required arguments: ')"
+
+- name: test create network acl in check mode
+ cs_network_acl:
+ name: "{{ cs_resource_prefix }}_acl"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl
+ check_mode: true
+- name: verify test create network acl in check mode
+ assert:
+ that:
+ - acl is successful
+ - acl is changed
+
+- name: test create network acl
+ cs_network_acl:
+ name: "{{ cs_resource_prefix }}_acl"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl
+- name: verify test create network acl
+ assert:
+ that:
+ - acl is successful
+ - acl is changed
+ - acl.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl.name == "{{ cs_resource_prefix }}_acl"
+
+- name: test create network acl idempotence
+ cs_network_acl:
+ name: "{{ cs_resource_prefix }}_acl"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl
+- name: verify test create network acl idempotence
+ assert:
+ that:
+ - acl is successful
+ - acl is not changed
+ - acl.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl.name == "{{ cs_resource_prefix }}_acl"
+
+- name: test remove network acl in check mode
+ cs_network_acl:
+ name: "{{ cs_resource_prefix }}_acl"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: acl
+ check_mode: true
+- name: verify test remove network acl in check mode
+ assert:
+ that:
+ - acl is successful
+ - acl is changed
+ - acl.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl.name == "{{ cs_resource_prefix }}_acl"
+
+- name: test remove network acl
+ cs_network_acl:
+ name: "{{ cs_resource_prefix }}_acl"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: acl
+- name: verify test remove network acl
+ assert:
+ that:
+ - acl is successful
+ - acl is changed
+ - acl.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl.name == "{{ cs_resource_prefix }}_acl"
+
+- name: test remove network acl idempotence
+ cs_network_acl:
+ name: "{{ cs_resource_prefix }}_acl"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: acl
+- name: verify test remove network acl idempotence
+ assert:
+ that:
+ - acl is successful
+ - acl is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/tasks/main.yml
new file mode 100644
index 00000000..06f5f5ae
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/tasks/main.yml
@@ -0,0 +1,548 @@
+---
+- name: setup vpc
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify setup vpc
+ assert:
+ that:
+ - vpc is successful
+
+- name: setup network acl
+ cs_network_acl:
+ name: "{{ cs_resource_prefix }}_acl"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl
+- name: verify setup network acl
+ assert:
+ that:
+ - acl is successful
+
+- name: setup network acl rule
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: acl_rule
+- name: verify setup network acl rule
+ assert:
+ that:
+ - acl_rule is successful
+
+- name: test fail missing params
+ cs_network_acl_rule:
+ ignore_errors: true
+ register: acl_rule
+- name: verify test fail missing param
+ assert:
+ that:
+ - acl_rule is failed
+ - "acl_rule.msg.startswith('missing required arguments: ')"
+
+- name: test fail missing params for tcp
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: ingress
+ action_policy: allow
+ cidr: 0.0.0.0/0
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: true
+ register: acl_rule
+- name: verify test fail missing param for tcp
+ assert:
+ that:
+ - acl_rule is failed
+ - "acl_rule.msg == 'protocol is tcp but the following are missing: start_port, end_port'"
+
+- name: test fail missing params for icmp
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: ingress
+ action_policy: allow
+ cidr: 0.0.0.0/0
+ protocol: icmp
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: true
+ register: acl_rule
+- name: verify test fail missing param for icmp
+ assert:
+ that:
+ - acl_rule is failed
+ - "acl_rule.msg == 'protocol is icmp but the following are missing: icmp_type, icmp_code'"
+
+- name: test fail missing params for by number
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: ingress
+ action_policy: allow
+ cidr: 0.0.0.0/0
+ protocol: by_number
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: true
+ register: acl_rule
+- name: verify test fail missing param for by number
+ assert:
+ that:
+ - acl_rule is failed
+ - "acl_rule.msg == 'protocol is by_number but the following are missing: protocol_number'"
+
+- name: test create network acl rule in check mode
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: ingress
+ action_policy: allow
+ port: 80
+ cidr: 0.0.0.0/0
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+ check_mode: true
+- name: verify test create network acl rule in check mode
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+
+- name: test create network acl rule
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: ingress
+ action_policy: allow
+ port: 80
+ cidr: 0.0.0.0/0
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+- name: verify test create network acl rule
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 80
+ - acl_rule.end_port == 80
+ - acl_rule.action_policy == "allow"
+ - acl_rule.cidr == "0.0.0.0/0"
+ - acl_rule.traffic_type == "ingress"
+ - acl_rule.rule_position == 1
+
+- name: test create network acl rule idempotence
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: ingress
+ action_policy: allow
+ port: 80
+ cidr: 0.0.0.0/0
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+- name: verify test create network acl idempotence
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is not changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 80
+ - acl_rule.end_port == 80
+ - acl_rule.action_policy == "allow"
+ - acl_rule.cidr == "0.0.0.0/0"
+ - acl_rule.traffic_type == "ingress"
+ - acl_rule.rule_position == 1
+
+- name: test change network acl rule in check mode
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: deny
+ port: 81
+ cidrs:
+ - 1.2.3.0/24
+ - 3.2.1.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+ check_mode: true
+- name: verify test change network acl rule in check mode
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 80
+ - acl_rule.end_port == 80
+ - acl_rule.action_policy == "allow"
+ - acl_rule.cidr == "0.0.0.0/0"
+ - acl_rule.cidrs == [ "0.0.0.0/0" ]
+ - acl_rule.traffic_type == "ingress"
+ - acl_rule.rule_position == 1
+
+- name: test change network acl rule
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: deny
+ port: 81
+ protocol: udp
+ cidrs:
+ - 1.2.3.0/24
+ - 3.2.1.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+- name: verify test change network acl rule
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 81
+ - acl_rule.end_port == 81
+ - acl_rule.action_policy == "deny"
+ - acl_rule.cidr == "1.2.3.0/24,3.2.1.0/24"
+ - acl_rule.cidrs == [ "1.2.3.0/24", "3.2.1.0/24" ]
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "udp"
+ - acl_rule.rule_position == 1
+
+- name: test change network acl rule idempotence
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: deny
+ port: 81
+ protocol: udp
+ cidrs:
+ - 1.2.3.0/24
+ - 3.2.1.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+- name: verify test change network acl idempotence
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is not changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 81
+ - acl_rule.end_port == 81
+ - acl_rule.action_policy == "deny"
+ - acl_rule.cidr == "1.2.3.0/24,3.2.1.0/24"
+ - acl_rule.cidrs == [ "1.2.3.0/24", "3.2.1.0/24" ]
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "udp"
+ - acl_rule.rule_position == 1
+
+- name: test change network acl by protocol number in check mode
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: deny
+ protocol: by_number
+ protocol_number: 8
+ port: 81
+ cidr: 0.0.0.0/0
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+ check_mode: true
+- name: verify test change network acl by protocol number in check mode
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 81
+ - acl_rule.end_port == 81
+ - acl_rule.action_policy == "deny"
+ - acl_rule.cidr == "1.2.3.0/24,3.2.1.0/24"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "udp"
+ - acl_rule.rule_position == 1
+
+- name: test change network acl by protocol number
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: deny
+ protocol: by_number
+ protocol_number: 8
+ port: 81
+ cidr: 0.0.0.0/0
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+- name: verify test change network acl by protocol number
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 81
+ - acl_rule.end_port == 81
+ - acl_rule.action_policy == "deny"
+ - acl_rule.cidr == "0.0.0.0/0"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "by_number"
+ - acl_rule.protocol_number == 8
+ - acl_rule.rule_position == 1
+
+- name: test change network acl by protocol number idempotence
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: deny
+ protocol: by_number
+ protocol_number: 8
+ port: 81
+ cidr: 0.0.0.0/0
+ zone: "{{ cs_common_zone_adv }}"
+ register: acl_rule
+- name: verify test change network acl by protocol number idempotence
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is not changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 81
+ - acl_rule.end_port == 81
+ - acl_rule.action_policy == "deny"
+ - acl_rule.cidr == "0.0.0.0/0"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "by_number"
+ - acl_rule.protocol_number == 8
+ - acl_rule.rule_position == 1
+
+
+- name: test create 2nd network acl rule in check mode
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 2
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: allow
+ cidr: 10.23.12.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ protocol: all
+ register: acl_rule
+ check_mode: true
+- name: verify test create 2nd network acl rule in check mode
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+
+- name: test create 2nd network acl rule
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 2
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: allow
+ cidr: 10.23.12.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ protocol: all
+ register: acl_rule
+- name: verify test create 2nd network acl rule
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.action_policy == "allow"
+ - acl_rule.cidr == "10.23.12.0/24"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "all"
+ - acl_rule.rule_position == 2
+
+- name: test create 2nd network acl rule idempotence
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 2
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: allow
+ cidr: 10.23.12.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ protocol: all
+ register: acl_rule
+- name: verify test create 2nd network acl rule idempotence
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is not changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.action_policy == "allow"
+ - acl_rule.cidr == "10.23.12.0/24"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "all"
+ - acl_rule.rule_position == 2
+
+- name: test update 2nd network acl rule to icmp
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 2
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: allow
+ cidr: 10.23.12.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ protocol: icmp
+ icmp_type: 0
+ icmp_code: 8
+ register: acl_rule
+- name: verify test create 2nd network acl rule
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.action_policy == "allow"
+ - acl_rule.cidr == "10.23.12.0/24"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "icmp"
+ - acl_rule.icmp_type == 0
+ - acl_rule.icmp_code == 8
+ - acl_rule.rule_position == 2
+
+- name: test update 2nd network acl rule to icmp idempotence
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 2
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ traffic_type: egress
+ action_policy: allow
+ cidr: 10.23.12.0/24
+ zone: "{{ cs_common_zone_adv }}"
+ protocol: icmp
+ icmp_type: 0
+ icmp_code: 8
+ register: acl_rule
+- name: verify test create 2nd network acl rule idempotence
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is not changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.action_policy == "allow"
+ - acl_rule.cidr == "10.23.12.0/24"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "icmp"
+ - acl_rule.icmp_type == 0
+ - acl_rule.icmp_code == 8
+ - acl_rule.rule_position == 2
+
+- name: test absent network acl rule in check mode
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: acl_rule
+ check_mode: true
+- name: verify test absent network acl rule in check mode
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 81
+ - acl_rule.end_port == 81
+ - acl_rule.action_policy == "deny"
+ - acl_rule.cidr == "0.0.0.0/0"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.rule_position == 1
+
+- name: test absent network acl rule
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: acl_rule
+- name: verify test absent network acl rule
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.start_port == 81
+ - acl_rule.end_port == 81
+ - acl_rule.action_policy == "deny"
+ - acl_rule.cidr == "0.0.0.0/0"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.rule_position == 1
+
+- name: test absent network acl rule idempotence
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 1
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: acl_rule
+- name: verify test absent network acl rule idempotence
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is not changed
+
+- name: test absent 2nd network acl rule
+ cs_network_acl_rule:
+ network_acl: "{{ cs_resource_prefix }}_acl"
+ rule_position: 2
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: acl_rule
+- name: verify test absent 2nd network acl rule
+ assert:
+ that:
+ - acl_rule is successful
+ - acl_rule is changed
+ - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc"
+ - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl"
+ - acl_rule.action_policy == "allow"
+ - acl_rule.cidr == "10.23.12.0/24"
+ - acl_rule.traffic_type == "egress"
+ - acl_rule.protocol == "icmp"
+ - acl_rule.icmp_type == 0
+ - acl_rule.icmp_code == 8
+ - acl_rule.rule_position == 2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/tasks/main.yml
new file mode 100644
index 00000000..62d9d3e9
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/tasks/main.yml
@@ -0,0 +1,434 @@
+---
+- name: setup
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ state: absent
+ register: netoffer
+- name: verify setup
+ assert:
+ that:
+ - netoffer is successful
+
+- name: test fail if missing name
+ action: cs_network_offering
+ register: netoffer
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - netoffer is failed
+ - 'netoffer.msg == "missing required arguments: name"'
+
+- name: test fail if missing params
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ register: netoffer
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - netoffer is failed
+ - 'netoffer.msg == "missing required arguments: display_text, guest_ip_type, supported_services, service_providers"'
+
+- name: test create network offer in check mode
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description"
+ guest_ip_type: Isolated
+ max_connections: 300
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ register: netoffer
+ check_mode: yes
+- name: verify results of network offer in check mode
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+
+- name: test create network offer
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description"
+ guest_ip_type: Isolated
+ max_connections: 300
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ register: netoffer
+- name: verify results of network offer
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test create network offer idempotence
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description"
+ guest_ip_type: Isolated
+ max_connections: 300
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ register: netoffer
+- name: verify results of create network offer idempotence
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is not changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test enabling existing network offer in check_mode
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ state: enabled
+ register: netoffer
+ check_mode: yes
+- name: verify results of enabling existing network offer in check_mode
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test enabling existing network offer
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ state: enabled
+ register: netoffer
+- name: verify results of enabling existing network offer
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Enabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test enabling existing network offer idempotence
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ state: enabled
+ register: netoffer
+- name: verify results of enabling existing network idempotence
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is not changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Enabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test disabling network offer in check_mode
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description"
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: netoffer
+ check_mode: yes
+- name: verify results of disabling network offer in check_mode
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Enabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test disabling network offer
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description"
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: netoffer
+- name: verify results of disabling network offer
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test disabling network offer idempotence
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description"
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: netoffer
+- name: verify results of disabling network idempotence
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is not changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test rename network offer in check_mode
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description renamed"
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: netoffer
+ check_mode: yes
+- name: verify results of rename network offer in check_mode
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test rename network offer
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description renamed"
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: netoffer
+- name: verify results of rename network offer
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description renamed"
+
+- name: test rename network offer idempotence
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description renamed"
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: netoffer
+- name: verify results of rename network offer idempotence
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is not changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description renamed"
+
+- name: test update offer with minimal params in check_mode
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description update"
+ max_connections: 400
+ register: netoffer
+ check_mode: yes
+- name: verify results of update offer with minimal params in check_mode
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description renamed"
+ - netoffer.max_connections == 300
+
+- name: test update offer with minimal params
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description update"
+ max_connections: 400
+ register: netoffer
+- name: verify results of update offer with minimal params
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description update"
+ - netoffer.max_connections == 400
+
+- name: test update offer with minimal params idempotency
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description update"
+ max_connections: 400
+ register: netoffer
+- name: verify results of update offer with minimal params idempotency
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is not changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description update"
+ - netoffer.max_connections == 400
+
+- name: test remove network offer in check_mode
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ state: absent
+ register: netoffer
+ check_mode: yes
+- name: verify results of rename network offer in check_mode
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description update"
+
+- name: test remove network offer
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ state: absent
+ register: netoffer
+- name: verify results of rename network offer
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Disabled"
+ - netoffer.display_text == "network offering description update"
+
+- name: test remove network offer idempotence
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ state: absent
+ register: netoffer
+- name: verify results of rename network offer idempotence
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is not changed
+
+- name: test create enabled network offer in check mode
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description"
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: enabled
+ register: netoffer
+ check_mode: yes
+- name: verify results of create enabled network offer in check mode
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+
+- name: test create enabled network offer
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description"
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: enabled
+ register: netoffer
+- name: verify results of create enabled network offer
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Enabled"
+ - netoffer.display_text == "network offering description"
+
+- name: test create enabled network offer idempotence
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ display_text: "network offering description"
+ guest_ip_type: Isolated
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: enabled
+ register: netoffer
+- name: verify results of create enabled network offer idempotence
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is not changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Enabled"
+ - netoffer.display_text == "network offering description"
+
+- name: remove network offer
+ cs_network_offering:
+ name: "{{ cs_resource_prefix }}_name"
+ state: absent
+ register: netoffer
+- name: verify results of remove network offer
+ assert:
+ that:
+ - netoffer is successful
+ - netoffer is changed
+ - netoffer.name == "{{ cs_resource_prefix }}_name"
+ - netoffer.guest_ip_type == "Isolated"
+ - netoffer.state == "Enabled"
+ - netoffer.display_text == "network offering description"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/tasks/main.yml
new file mode 100644
index 00000000..4b986a6b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/tasks/main.yml
@@ -0,0 +1,232 @@
+---
+# Create a new zone - the default one is enabled
+- name: assure zone for tests
+ cs_zone:
+ name: cs-test-zone
+ state: present
+ dns1: 8.8.8.8
+ network_type: Advanced
+ register: cszone
+
+- name: ensure the zone is disabled
+ cs_zone:
+ name: "{{ cszone.name }}"
+ state: disabled
+ register: cszone
+
+- name: ensure a network is absent
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ state: absent
+
+- name: setup a network in check_mode
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ isolation_method: VLAN
+ broadcast_domain_range: ZONE
+ check_mode: yes
+ register: pn
+- name: validate setup a network
+ assert:
+ that:
+ - pn is changed
+ - pn.zone == cszone.name
+
+- name: setup a network
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ isolation_method: VLAN
+ broadcast_domain_range: ZONE
+ register: pn
+- name: validate setup a network
+ assert:
+ that:
+ - pn is changed
+ - pn.name == 'net01'
+ - pn.broadcast_domain_range == 'ZONE'
+ - pn.isolation_method == 'VLAN'
+ - pn.zone == cszone.name
+ - pn.state == 'Disabled'
+
+- name: setup a network idempotence
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ isolation_method: VLAN
+ broadcast_domain_range: ZONE
+ register: pn
+- name: validate setup a network idempotence
+ assert:
+ that:
+ - pn is not changed
+ - pn.name == 'net01'
+ - pn.broadcast_domain_range == 'ZONE'
+ - pn.isolation_method == 'VLAN'
+ - pn.zone == cszone.name
+ - pn.state == 'Disabled'
+
+- name: set a tag on a network
+ cs_physical_network:
+ name: net01
+ tag: overlay
+ zone: "{{ cszone.name }}"
+ ignore_errors: true
+ register: pn
+- name: validate set a tag on a network
+ assert:
+ that:
+ - pn is changed
+ - pn.name == 'net01'
+ - pn.broadcast_domain_range == 'ZONE'
+ - pn.isolation_method == 'VLAN'
+ - pn.zone == cszone.name
+ - pn.tags == 'overlay'
+ - pn.state == 'Disabled'
+
+- name: Remove tag on a network
+ cs_physical_network:
+ name: net01
+ tag: ""
+ zone: "{{ cszone.name }}"
+ register: pn
+- name: validate remove tag on a network
+ assert:
+ that:
+ - pn is changed
+ - pn.name == 'net01'
+ - pn.broadcast_domain_range == 'ZONE'
+ - pn.isolation_method == 'VLAN'
+ - pn.zone == cszone.name
+ - pn.tags is undefined
+ - pn.state == 'Disabled'
+
+- name: ensure a network is enabled with specific nsps enabled in check mode
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ isolation_method: VLAN
+ vlan: 100-200,300-400
+ broadcast_domain_range: ZONE
+ state: enabled
+ nsps_enabled:
+ - virtualrouter
+ - internallbvm
+ - vpcvirtualrouter
+ check_mode: yes
+ register: pn
+- name: validate ensure a network is enabled with specific nsps enabled in check mode
+ assert:
+ that:
+ - pn is changed
+ - pn.name == 'net01'
+ - pn.zone == cszone.name
+ - "'internallbvm' in pn.nsps_enabled"
+ - "'virtualrouter' in pn.nsps_enabled"
+ - "'vpcvirtualrouter' in pn.nsps_enabled"
+
+- name: ensure a network is enabled with specific nsps enabled
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ isolation_method: VLAN
+ vlan: 100-200,300-400
+ broadcast_domain_range: ZONE
+ state: enabled
+ nsps_enabled:
+ - virtualrouter
+ - internallbvm
+ - vpcvirtualrouter
+ register: pn
+- name: validate ensure a network is enabled with specific nsps enabled
+ assert:
+ that:
+ - pn is changed
+ - pn.name == 'net01'
+ - pn.broadcast_domain_range == 'ZONE'
+ - pn.isolation_method == 'VLAN'
+ - pn.zone == cszone.name
+ - pn.vlan == '100-200,300-400'
+ - pn.state == 'Enabled'
+ - "'internallbvm' in pn.nsps_enabled"
+ - "'virtualrouter' in pn.nsps_enabled"
+ - "'vpcvirtualrouter' in pn.nsps_enabled"
+
+- name: ensure a network is disabled
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ state: disabled
+ register: pn
+- name: validate ensure a network is disabled
+ assert:
+ that:
+ - pn is changed
+ - pn.name == 'net01'
+ - pn.broadcast_domain_range == 'ZONE'
+ - pn.isolation_method == 'VLAN'
+ - pn.zone == cszone.name
+ - pn.tags is undefined
+ - pn.state == 'Disabled'
+
+- name: ensure a network is enabled
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ state: enabled
+ register: pn
+- name: validate ensure a network is enabled
+ assert:
+ that:
+ - pn is changed
+ - pn.name == 'net01'
+ - pn.broadcast_domain_range == 'ZONE'
+ - pn.isolation_method == 'VLAN'
+ - pn.zone == cszone.name
+ - pn.tags is undefined
+ - pn.state == 'Enabled'
+
+- name: ensure a network is not absent in check mode
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ state: absent
+ check_mode: yes
+ register: pn
+- name: validate ensure a network is absent
+ assert:
+ that:
+ - pn is changed
+ - pn.zone == cszone.name
+
+- name: ensure a network is absent
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ state: absent
+ register: pn
+- name: validate ensure a network is absent
+ assert:
+ that:
+ - pn is changed
+ - pn.zone == cszone.name
+ - pn.name == 'net01'
+
+- name: ensure a network is absent idempotence
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ state: absent
+ register: pn
+- name: validate ensure a network is absent idempotence
+ assert:
+ that:
+ - pn is not changed
+ - pn.zone == cszone.name
+
+- name: cleanup zone
+ cs_zone:
+ name: "{{ cszone.name }}"
+ state: absent
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/aliases
new file mode 100644
index 00000000..c89c86d7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/tasks/main.yml
new file mode 100644
index 00000000..600bc22b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/tasks/main.yml
@@ -0,0 +1,301 @@
+---
+- name: setup zone is present
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ network_type: Basic
+ register: zone
+- name: verify setup zone is present
+ assert:
+ that:
+ - zone is successful
+
+- name: setup pod is absent
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: pod
+- name: verify setup pod is absent
+ assert:
+ that:
+ - pod is successful
+
+- name: test fail if missing name
+ cs_pod:
+ register: pod
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - pod is failed
+ - "pod.msg == 'missing required arguments: name'"
+
+
+- name: test create pod in check mode
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ start_ip: 10.100.10.101
+ gateway: 10.100.10.1
+ netmask: 255.255.255.0
+ register: pod_origin
+ check_mode: true
+- name: verify test create pod in check mode
+ assert:
+ that:
+ - pod_origin is changed
+ - pod_origin.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test create pod
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ start_ip: 10.100.10.101
+ gateway: 10.100.10.1
+ netmask: 255.255.255.0
+ register: pod_origin
+- name: verify test create pod
+ assert:
+ that:
+ - pod_origin is changed
+ - pod_origin.allocation_state == "Enabled"
+ - pod_origin.start_ip == "10.100.10.101"
+ - pod_origin.end_ip == "10.100.10.254"
+ - pod_origin.gateway == "10.100.10.1"
+ - pod_origin.netmask == "255.255.255.0"
+ - pod_origin.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test create pod idempotence
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ start_ip: 10.100.10.101
+ gateway: 10.100.10.1
+ netmask: 255.255.255.0
+ register: pod
+- name: verify test create pod idempotence
+ assert:
+ that:
+ - pod is not changed
+ - pod.allocation_state == "Enabled"
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.1"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test update pod in check mode
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ gateway: 10.100.10.2
+ netmask: 255.255.255.0
+ register: pod
+ check_mode: true
+- name: verify test update pod in check mode
+ assert:
+ that:
+ - pod is changed
+ - pod.allocation_state == "Enabled"
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.1"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test update pod
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ gateway: 10.100.10.2
+ netmask: 255.255.255.0
+ register: pod
+- name: verify test update pod
+ assert:
+ that:
+ - pod is changed
+ - pod.allocation_state == "Enabled"
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test update pod idempotence
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ gateway: 10.100.10.2
+ netmask: 255.255.255.0
+ register: pod
+- name: verify test update pod idempotence
+ assert:
+ that:
+ - pod is not changed
+ - pod.allocation_state == "Enabled"
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test disable pod in check mode
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: disabled
+ register: pod
+ check_mode: true
+- name: verify test enable pod in check mode
+ assert:
+ that:
+ - pod is changed
+ - pod.allocation_state == "Enabled"
+ - pod.id == pod_origin.id
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test disable pod
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: disabled
+ register: pod
+- name: verify test enable pod
+ assert:
+ that:
+ - pod is changed
+ - pod.allocation_state == "Disabled"
+ - pod.id == pod_origin.id
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test disable pod idempotence
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: disabled
+ register: pod
+- name: verify test enable pod idempotence
+ assert:
+ that:
+ - pod is not changed
+ - pod.allocation_state == "Disabled"
+ - pod.id == pod_origin.id
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test enable pod in check mode
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: enabled
+ register: pod
+ check_mode: true
+- name: verify test disable pod in check mode
+ assert:
+ that:
+ - pod is changed
+ - pod.allocation_state == "Disabled"
+ - pod.id == pod_origin.id
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test enable pod
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: enabled
+ register: pod
+- name: verify test disable pod
+ assert:
+ that:
+ - pod is changed
+ - pod.allocation_state == "Enabled"
+ - pod.id == pod_origin.id
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+
+- name: test enable pod idempotence
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: enabled
+ register: pod
+- name: verify test enabled pod idempotence
+ assert:
+ that:
+ - pod is not changed
+ - pod.allocation_state == "Enabled"
+ - pod.id == pod_origin.id
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test absent pod in check mode
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: pod
+ check_mode: true
+- name: verify test create pod in check mode
+ assert:
+ that:
+ - pod is changed
+ - pod.id == pod_origin.id
+ - pod.allocation_state == "Enabled"
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test absent pod
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: pod
+- name: verify test create pod
+ assert:
+ that:
+ - pod is changed
+ - pod.id == pod_origin.id
+ - pod.allocation_state == "Enabled"
+ - pod.start_ip == "10.100.10.101"
+ - pod.end_ip == "10.100.10.254"
+ - pod.gateway == "10.100.10.2"
+ - pod.netmask == "255.255.255.0"
+ - pod.zone == "{{ cs_resource_prefix }}-zone"
+
+- name: test absent pod idempotence
+ cs_pod:
+ name: "{{ cs_resource_prefix }}-pod"
+ zone: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: pod
+- name: verify test absent pod idempotence
+ assert:
+ that:
+ - pod is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/defaults/main.yml
new file mode 100644
index 00000000..89842c55
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+cs_portforward_public_ip: "10.100.212.5"
+cs_portforward_vm: "cs-{{ cs_resource_prefix }}-pf-vm"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/tasks/main.yml
new file mode 100644
index 00000000..d1b6946e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/tasks/main.yml
@@ -0,0 +1,255 @@
+---
+- name: network setup
+ cs_network:
+ name: ansible test
+ network_offering: DefaultIsolatedNetworkOfferingWithSourceNatService
+ network_domain: example.com
+ zone: "{{ cs_common_zone_adv }}"
+ register: net
+- name: verify network setup
+ assert:
+ that:
+ - net is successful
+
+- name: instance setup
+ cs_instance:
+ name: "{{ cs_portforward_vm }}"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ network: "ansible test"
+ register: instance
+- name: verify instance setup
+ assert:
+ that:
+ - instance is successful
+
+- name: public ip address setup
+ cs_ip_address:
+ network: ansible test
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+- name: verify public ip address setup
+ assert:
+ that:
+ - ip_address is successful
+
+- name: set ip address as fact
+ set_fact:
+ cs_portforward_public_ip: "{{ ip_address.ip_address }}"
+
+- name: clear existing port forwarding
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ private_port: 8080
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+- name: verify clear existing port forwarding
+ assert:
+ that:
+ - pf is successful
+
+- name: test fail if missing params
+ action: cs_portforward
+ register: pf
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - pf is failed
+ - 'pf.msg.startswith("missing required arguments: ")'
+
+- name: test present port forwarding in check mode
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ vm: "{{ cs_portforward_vm }}"
+ private_port: 8080
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+ check_mode: true
+- name: verify results of present port forwarding in check mode
+ assert:
+ that:
+ - pf is successful
+ - pf is changed
+
+- name: test present port forwarding
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ vm: "{{ cs_portforward_vm }}"
+ private_port: 8080
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+- name: verify results of present port forwarding
+ assert:
+ that:
+ - pf is successful
+ - pf is changed
+ - pf.vm_name == "{{ cs_portforward_vm }}"
+ - pf.ip_address == "{{ cs_portforward_public_ip }}"
+ - pf.public_port == 80
+ - pf.public_end_port == 80
+ - pf.private_port == 8080
+ - pf.private_end_port == 8080
+
+- name: test present port forwarding idempotence
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ vm: "{{ cs_portforward_vm }}"
+ private_port: 8080
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+- name: verify results of present port forwarding idempotence
+ assert:
+ that:
+ - pf is successful
+ - pf is not changed
+ - pf.vm_name == "{{ cs_portforward_vm }}"
+ - pf.ip_address == "{{ cs_portforward_public_ip }}"
+ - pf.public_port == 80
+ - pf.public_end_port == 80
+ - pf.private_port == 8080
+ - pf.private_end_port == 8080
+
+- name: test change port forwarding in check mode
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ vm: "{{ cs_portforward_vm }}"
+ private_port: 8888
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+ check_mode: true
+- name: verify results of change port forwarding in check mode
+ assert:
+ that:
+ - pf is successful
+ - pf is changed
+ - pf.vm_name == "{{ cs_portforward_vm }}"
+ - pf.ip_address == "{{ cs_portforward_public_ip }}"
+ - pf.public_port == 80
+ - pf.public_end_port == 80
+ - pf.private_port == 8080
+ - pf.private_end_port == 8080
+
+- name: test change port forwarding
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ vm: "{{ cs_portforward_vm }}"
+ private_port: 8888
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+- name: verify results of change port forwarding
+ assert:
+ that:
+ - pf is successful
+ - pf is changed
+ - pf.vm_name == "{{ cs_portforward_vm }}"
+ - pf.ip_address == "{{ cs_portforward_public_ip }}"
+ - pf.public_port == 80
+ - pf.public_end_port == 80
+ - pf.private_port == 8888
+ - pf.private_end_port == 8888
+
+- name: test change port forwarding idempotence
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ vm: "{{ cs_portforward_vm }}"
+ private_port: 8888
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+- name: verify results of change port forwarding idempotence
+ assert:
+ that:
+ - pf is successful
+ - pf is not changed
+ - pf.vm_name == "{{ cs_portforward_vm }}"
+ - pf.ip_address == "{{ cs_portforward_public_ip }}"
+ - pf.public_port == 80
+ - pf.public_end_port == 80
+ - pf.private_port == 8888
+ - pf.private_end_port == 8888
+
+- name: test absent port forwarding in check mode
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ private_port: 8888
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+ check_mode: true
+- name: verify results of absent port forwarding in check mode
+ assert:
+ that:
+ - pf is successful
+ - pf is changed
+ - pf.vm_name == "{{ cs_portforward_vm }}"
+ - pf.ip_address == "{{ cs_portforward_public_ip }}"
+ - pf.public_port == 80
+ - pf.public_end_port == 80
+ - pf.private_port == 8888
+ - pf.private_end_port == 8888
+
+- name: test absent port forwarding
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ private_port: 8888
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+- name: verify results of absent port forwarding
+ assert:
+ that:
+ - pf is successful
+ - pf is changed
+ - pf.vm_name == "{{ cs_portforward_vm }}"
+ - pf.ip_address == "{{ cs_portforward_public_ip }}"
+ - pf.public_port == 80
+ - pf.public_end_port == 80
+ - pf.private_port == 8888
+ - pf.private_end_port == 8888
+
+- name: test absent port forwarding idempotence
+ cs_portforward:
+ ip_address: "{{ cs_portforward_public_ip }}"
+ public_port: 80
+ private_port: 8888
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: pf
+- name: verify results of absent port forwarding idempotence
+ assert:
+ that:
+ - pf is successful
+ - pf is not changed
+
+- name: instance cleanup
+ cs_instance:
+ name: "{{ cs_portforward_vm }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+ register: instance
+- name: verify instance cleanup
+ assert:
+ that:
+ - instance is successful
+
+- name: network cleanup
+ cs_network:
+ name: ansible test
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: net
+- name: verify network cleanup
+ assert:
+ that:
+ - net is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/tasks/main.yml
new file mode 100644
index 00000000..7ece89d4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/tasks/main.yml
@@ -0,0 +1,149 @@
+---
+- name: ensure project does not exist
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: prj
+- name: verify project did not exist
+ assert:
+ that:
+ - prj is successful
+
+- name: test create project in check mode
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ register: prj
+ check_mode: true
+- name: verify test create project in check mode
+ assert:
+ that:
+ - prj is changed
+
+- name: test create project
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ register: prj
+- name: verify test create project
+ assert:
+ that:
+ - prj is changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+
+- name: test create project idempotence
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ register: prj
+- name: verify test create project idempotence
+ assert:
+ that:
+ - prj is not changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+
+- name: test suspend project in check mode
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: suspended
+ register: prj
+ check_mode: true
+- name: verify test suspend project in check mode
+ assert:
+ that:
+ - prj is changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+ - prj.state != "Suspended"
+
+- name: test suspend project
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: suspended
+ register: prj
+- name: verify test suspend project
+ assert:
+ that:
+ - prj is changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+ - prj.state == "Suspended"
+
+- name: test suspend project idempotence
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: suspended
+ register: prj
+- name: verify test suspend project idempotence
+ assert:
+ that:
+ - prj is not changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+ - prj.state == "Suspended"
+
+- name: test activate project in check mode
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: active
+ register: prj
+ check_mode: true
+- name: verify test activate project in check mode
+ assert:
+ that:
+ - prj is changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+ - prj.state != "Active"
+
+- name: test activate project
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: active
+ register: prj
+- name: verify test activate project
+ assert:
+ that:
+ - prj is changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+ - prj.state == "Active"
+
+- name: test activate project idempotence
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: active
+ register: prj
+- name: verify test activate project idempotence
+ assert:
+ that:
+ - prj is not changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+ - prj.state == "Active"
+
+- name: test delete project in check mode
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: prj
+ check_mode: true
+- name: verify test delete project in check mode
+ assert:
+ that:
+ - prj is changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+ - prj.state == "Active"
+
+- name: test delete project
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: prj
+- name: verify test delete project
+ assert:
+ that:
+ - prj is changed
+ - prj.name == "{{ cs_resource_prefix }}-prj"
+ - prj.state == "Active"
+
+- name: test delete project idempotence
+ cs_project:
+ name: "{{ cs_resource_prefix }}-prj"
+ state: absent
+ register: prj
+- name: verify test delete project idempotence
+ assert:
+ that:
+ - prj is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/tasks/main.yml
new file mode 100644
index 00000000..d7283083
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/tasks/main.yml
@@ -0,0 +1,154 @@
+---
+- name: setup
+ cs_region:
+ id: 2
+ state: absent
+ register: region
+- name: verify setup
+ assert:
+ that:
+ - region is successful
+
+- name: test fail if missing params
+ cs_region:
+ register: region
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - region is failed
+ - "region.msg.startswith('missing required arguments: ')"
+
+- name: test create region in check mode
+ cs_region:
+ id: 2
+ name: geneva
+ endpoint: https://cloud.gva.example.com
+ register: region
+ check_mode: true
+- name: verify test create region in check mode
+ assert:
+ that:
+ - region is changed
+
+- name: test create region in check mode
+ cs_region:
+ id: 2
+ name: geneva
+ endpoint: https://cloud.gva.example.com
+ register: region
+- name: verify test create region in check mode
+ assert:
+ that:
+ - region is changed
+ - region.name == 'geneva'
+ - region.id == 2
+ - region.endpoint == 'https://cloud.gva.example.com'
+ - region.gslb_service_enabled == true
+ - region.portable_ip_service_enabled == false
+
+- name: test create region idempotence
+ cs_region:
+ id: 2
+ name: geneva
+ endpoint: https://cloud.gva.example.com
+ register: region
+- name: verify test create region idempotence
+ assert:
+ that:
+ - region is not changed
+ - region.name == 'geneva'
+ - region.id == 2
+ - region.endpoint == 'https://cloud.gva.example.com'
+ - region.gslb_service_enabled == true
+ - region.portable_ip_service_enabled == false
+
+- name: test update region in check mode
+ cs_region:
+ id: 2
+ name: zuerich
+ endpoint: https://cloud.zrh.example.com
+ register: region
+ check_mode: true
+- name: verify test update region in check mode
+ assert:
+ that:
+ - region is changed
+ - region.name == 'geneva'
+ - region.id == 2
+ - region.endpoint == 'https://cloud.gva.example.com'
+ - region.gslb_service_enabled == true
+ - region.portable_ip_service_enabled == false
+
+- name: test update region
+ cs_region:
+ id: 2
+ name: zuerich
+ endpoint: https://cloud.zrh.example.com
+ register: region
+- name: verify test update region
+ assert:
+ that:
+ - region is changed
+ - region.name == 'zuerich'
+ - region.id == 2
+ - region.endpoint == 'https://cloud.zrh.example.com'
+ - region.gslb_service_enabled == true
+ - region.portable_ip_service_enabled == false
+
+- name: test update region idempotence
+ cs_region:
+ id: 2
+ name: zuerich
+ endpoint: https://cloud.zrh.example.com
+ register: region
+- name: verify test update region idempotence
+ assert:
+ that:
+ - region is not changed
+ - region.name == 'zuerich'
+ - region.id == 2
+ - region.endpoint == 'https://cloud.zrh.example.com'
+ - region.gslb_service_enabled == true
+ - region.portable_ip_service_enabled == false
+
+- name: test remove region in check mdoe
+ cs_region:
+ id: 2
+ state: absent
+ register: region
+ check_mode: true
+- name: verify test remove region in check mode
+ assert:
+ that:
+ - region is changed
+ - region.name == 'zuerich'
+ - region.id == 2
+ - region.endpoint == 'https://cloud.zrh.example.com'
+ - region.gslb_service_enabled == true
+ - region.portable_ip_service_enabled == false
+
+- name: test remove region
+ cs_region:
+ id: 2
+ state: absent
+ register: region
+- name: verify test remove region
+ assert:
+ that:
+ - region is changed
+ - region.name == 'zuerich'
+ - region.id == 2
+ - region.endpoint == 'https://cloud.zrh.example.com'
+ - region.gslb_service_enabled == true
+ - region.portable_ip_service_enabled == false
+
+- name: test remove region idempotence
+ cs_region:
+ id: 2
+ state: absent
+ register: region
+- name: verify test remove region idempotence
+ assert:
+ that:
+ - region is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/cpu.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/cpu.yml
new file mode 100644
index 00000000..baa736b4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/cpu.yml
@@ -0,0 +1,122 @@
+---
+- name: setup cpu limits account
+ cs_resourcelimit:
+ type: cpu
+ limit: 20
+ account: "{{ cs_resource_prefix }}_user"
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify setup cpu limits account
+ assert:
+ that:
+ - rl is successful
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.account == "{{ cs_resource_prefix }}_user"
+ - rl.limit == 20
+ - rl.resource_type == "cpu"
+
+- name: setup cpu limits for domain
+ cs_resourcelimit:
+ type: cpu
+ limit: -1
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify setup cpu limits for domain
+ assert:
+ that:
+ - rl is successful
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == -1
+ - rl.resource_type == "cpu"
+
+- name: set cpu limits for domain in check mode
+ cs_resourcelimit:
+ type: cpu
+ limit: 12
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+ check_mode: true
+- name: verify set cpu limits for domain in check mode
+ assert:
+ that:
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == -1
+ - rl.resource_type == "cpu"
+
+- name: set cpu limits for domain
+ cs_resourcelimit:
+ type: cpu
+ limit: 12
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify set cpu limits for domain
+ assert:
+ that:
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == 12
+ - rl.resource_type == "cpu"
+
+- name: set cpu limits for domain idempotence
+ cs_resourcelimit:
+ type: cpu
+ limit: 12
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify set cpu limits for domain
+ assert:
+ that:
+ - rl is not changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == 12
+ - rl.resource_type == "cpu"
+
+- name: set cpu limits for account in check mode
+ cs_resourcelimit:
+ type: cpu
+ limit: 10
+ account: "{{ cs_resource_prefix }}_user"
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+ check_mode: true
+- name: verify set cpu limits for account in check mode
+ assert:
+ that:
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.account == "{{ cs_resource_prefix }}_user"
+ - rl.limit == 20
+ - rl.resource_type == "cpu"
+
+- name: set cpu limits for account
+ cs_resourcelimit:
+ type: cpu
+ limit: 10
+ account: "{{ cs_resource_prefix }}_user"
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify set cpu limits for account
+ assert:
+ that:
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.account == "{{ cs_resource_prefix }}_user"
+ - rl.limit == 10
+ - rl.resource_type == "cpu"
+
+- name: set cpu limits for account idempotence
+ cs_resourcelimit:
+ type: cpu
+ limit: 10
+ account: "{{ cs_resource_prefix }}_user"
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify set cpu limits for account idempotence
+ assert:
+ that:
+ - rl is not changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.account == "{{ cs_resource_prefix }}_user"
+ - rl.limit == 10
+ - rl.resource_type == "cpu"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/instance.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/instance.yml
new file mode 100644
index 00000000..11a1fe07
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/instance.yml
@@ -0,0 +1,108 @@
+---
+- name: setup instance limits account
+ cs_resourcelimit:
+ type: instance
+ limit: 20
+ account: "{{ cs_resource_prefix }}_user"
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify setup instance limits account
+ assert:
+ that:
+ - rl is successful
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.account == "{{ cs_resource_prefix }}_user"
+ - rl.limit == 20
+ - rl.resource_type == "instance"
+
+- name: set instance limits for domain in check mode
+ cs_resourcelimit:
+ type: instance
+ limit: 12
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+ check_mode: true
+- name: verify set instance limits for domain in check mode
+ assert:
+ that:
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == 20
+ - rl.resource_type == "instance"
+
+- name: set instance limits for domain
+ cs_resourcelimit:
+ type: instance
+ limit: 12
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify set instance limits for domain
+ assert:
+ that:
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == 12
+ - rl.resource_type == "instance"
+
+- name: set instance limits for domain idempotence
+ cs_resourcelimit:
+ type: instance
+ limit: 12
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify set instance limits for domain
+ assert:
+ that:
+ - rl is not changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == 12
+ - rl.resource_type == "instance"
+
+- name: set instance limits for account in check mode
+ cs_resourcelimit:
+ type: instance
+ limit: 10
+ account: "{{ cs_resource_prefix }}_user"
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+ check_mode: true
+- name: verify set instance limits for account in check mode
+ assert:
+ that:
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.account == "{{ cs_resource_prefix }}_user"
+ - rl.limit != 10
+ - rl.resource_type == "instance"
+
+- name: set instance limits for account
+ cs_resourcelimit:
+ type: instance
+ limit: 10
+ account: "{{ cs_resource_prefix }}_user"
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify set instance limits for account
+ assert:
+ that:
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.account == "{{ cs_resource_prefix }}_user"
+ - rl.limit == 10
+ - rl.resource_type == "instance"
+
+- name: set instance limits for account idempotence
+ cs_resourcelimit:
+ type: instance
+ limit: 10
+ account: "{{ cs_resource_prefix }}_user"
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify set instance limits for account idempotence
+ assert:
+ that:
+ - rl is not changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.account == "{{ cs_resource_prefix }}_user"
+ - rl.limit == 10
+ - rl.resource_type == "instance"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/main.yml
new file mode 100644
index 00000000..fcf9279f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/main.yml
@@ -0,0 +1,104 @@
+---
+- name: setup domain
+ cs_domain: path={{ cs_resource_prefix }}-domain
+ register: dom
+- name: verify setup domain
+ assert:
+ that:
+ - dom is successful
+
+- name: setup account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_user"
+ username: "{{ cs_resource_prefix }}_username"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ network_domain: "{{ cs_resource_prefix }}-local"
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: acc
+- name: verify setup account
+ assert:
+ that:
+ - acc is successful
+
+- name: test failed unkonwn type
+ cs_resourcelimit:
+ type: unkonwn
+ limit: 20
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+ ignore_errors: yes
+- name: verify test failed unkonwn type
+ assert:
+ that:
+ - rl is failed
+
+- name: test failed missing type
+ cs_resourcelimit:
+ register: rl
+ ignore_errors: yes
+- name: verify test failed missing type
+ assert:
+ that:
+ - rl is failed
+
+- name: setup resource limits domain
+ cs_resourcelimit:
+ type: instance
+ limit: 10
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify setup resource limits domain
+ assert:
+ that:
+ - rl is successful
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == 10
+
+- name: set resource limits domain to 20 in check mode
+ cs_resourcelimit:
+ type: instance
+ limit: 20
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+ check_mode: true
+- name: verify setup resource limits domain to 20 in check mode
+ assert:
+ that:
+ - rl is successful
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == 10
+
+- name: set resource limits domain to 20
+ cs_resourcelimit:
+ type: instance
+ limit: 20
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify setup resource limits domain to 20
+ assert:
+ that:
+ - rl is successful
+ - rl is changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == 20
+
+- name: set resource limits domain to 20 idempotence
+ cs_resourcelimit:
+ type: instance
+ limit: 20
+ domain: "{{ cs_resource_prefix }}-domain"
+ register: rl
+- name: verify setup resource limits domain to 20 idempotence
+ assert:
+ that:
+ - rl is successful
+ - rl is not changed
+ - rl.domain == "{{ cs_resource_prefix }}-domain"
+ - rl.limit == 20
+
+- include: instance.yml
+- include: cpu.yml
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/tasks/main.yml
new file mode 100644
index 00000000..11c1653d
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/tasks/main.yml
@@ -0,0 +1,130 @@
+---
+- name: setup
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ state: absent
+ register: role
+- name: verify setup
+ assert:
+ that:
+ - role is successful
+
+- name: test fail if missing params
+ cs_role:
+ register: role
+ ignore_errors: true
+- name: verifytest fail if missing params
+ assert:
+ that:
+ - role is failed
+ - "role.msg.startswith('missing required arguments: ')"
+
+- name: test create role in check mode
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ role_type: DomainAdmin
+ register: role
+ check_mode: true
+- name: verify test create role in check mode
+ assert:
+ that:
+ - role is changed
+
+- name: test create role
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ role_type: DomainAdmin
+ register: role
+- name: verify test create role
+ assert:
+ that:
+ - role is changed
+ - role.name == '{{ cs_resource_prefix }}-role'
+ - role.role_type == 'DomainAdmin'
+
+- name: test create role idempotence
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ role_type: DomainAdmin
+ register: role
+- name: verify test create role idempotence
+ assert:
+ that:
+ - role is not changed
+ - role.name == '{{ cs_resource_prefix }}-role'
+ - role.role_type == 'DomainAdmin'
+
+- name: test update role in check mode
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ description: "{{ cs_resource_prefix }}-role-description"
+ role_type: DomainAdmin
+ register: role
+ check_mode: true
+- name: verify test update role in check mode
+ assert:
+ that:
+ - role is changed
+ - role.name == '{{ cs_resource_prefix }}-role'
+ - "role.description is not defined"
+ - role.role_type == 'DomainAdmin'
+
+- name: test update role
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ description: "{{ cs_resource_prefix }}-role-description"
+ role_type: DomainAdmin
+ register: role
+- name: verify test update role
+ assert:
+ that:
+ - role is changed
+ - role.name == '{{ cs_resource_prefix }}-role'
+ - role.description == '{{ cs_resource_prefix }}-role-description'
+ - role.role_type == 'DomainAdmin'
+
+- name: test update role idempotence
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ description: "{{ cs_resource_prefix }}-role-description"
+ register: role
+- name: verify test update role idempotence
+ assert:
+ that:
+ - role is not changed
+ - role.name == '{{ cs_resource_prefix }}-role'
+ - role.description == '{{ cs_resource_prefix }}-role-description'
+ - role.role_type == 'DomainAdmin'
+
+- name: test remove role in check mdoe
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ state: absent
+ register: role
+ check_mode: true
+- name: verify test remove role in check mode
+ assert:
+ that:
+ - role is changed
+ - role.name == '{{ cs_resource_prefix }}-role'
+ - role.role_type == 'DomainAdmin'
+
+- name: test remove role
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ state: absent
+ register: role
+- name: verify test remove role
+ assert:
+ that:
+ - role is changed
+
+- name: test remove role idempotence
+ cs_role:
+ name: "{{ cs_resource_prefix }}-role"
+ state: absent
+ register: role
+- name: verify test remove role idempotence
+ assert:
+ that:
+ - role is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/tasks/main.yml
new file mode 100644
index 00000000..95e2df84
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/tasks/main.yml
@@ -0,0 +1,303 @@
+- name: pre-setup
+ cs_role:
+ name: "testRole"
+ register: testRole
+- name: verify pre-setup
+ assert:
+ that:
+ - testRole is successful
+
+- name: setup
+ cs_role_permission:
+ name: "fakeRolePerm"
+ role: "{{ testRole.id }}"
+ state: absent
+ register: roleperm
+- name: verify setup
+ assert:
+ that:
+ - roleperm is successful
+
+- name: setup2
+ cs_role_permission:
+ name: "fakeRolePerm2"
+ role: "{{ testRole.id }}"
+ state: absent
+ register: roleperm2
+- name: verify setup2
+ assert:
+ that:
+ - roleperm2 is successful
+
+- name: test fail if missing name
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ register: roleperm
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - roleperm is failed
+ - 'roleperm.msg == "missing required arguments: name"'
+
+- name: test fail if missing role
+ cs_role_permission:
+ name: "fakeRolePerm"
+ register: roleperm
+ ignore_errors: true
+- name: verify results of fail if missing role
+ assert:
+ that:
+ - roleperm is failed
+ - 'roleperm.msg == "missing required arguments: role"'
+
+- name: test fail if role does not exist
+ cs_role_permission:
+ name: "fakeRolePerm"
+ role: "testtest"
+ register: roleperm
+ ignore_errors: true
+- name: verify results of fail if role does not exist
+ assert:
+ that:
+ - roleperm is failed
+ - roleperm.msg == "Role 'testtest' not found"
+
+- name: test fail if state is incorrcect
+ cs_role_permission:
+ state: badstate
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ permission: allow
+ register: roleperm
+ ignore_errors: true
+- name: verify results of fail if state is incorrcect
+ assert:
+ that:
+ - roleperm is failed
+ - 'roleperm.msg == "value of state must be one of: present, absent, got: badstate"'
+
+- name: test create role permission in check mode
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ permission: allow
+ description: "fakeRolePerm description"
+ register: roleperm
+ check_mode: yes
+- name: verify results of role permission in check mode
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+
+- name: test create role permission
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ permission: allow
+ description: "fakeRolePerm description"
+ register: roleperm
+- name: verify results of role permission
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+ - roleperm.name == "fakeRolePerm"
+ - roleperm.permission == "allow"
+ - roleperm.description == "fakeRolePerm description"
+
+- name: test create role permission idempotency
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ permission: allow
+ description: "fakeRolePerm description"
+ register: roleperm
+- name: verify results of role permission idempotency
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is not changed
+ - roleperm.name == "fakeRolePerm"
+ - roleperm.permission == "allow"
+ - roleperm.description == "fakeRolePerm description"
+
+- name: test update role permission in check_mode
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ permission: deny
+ description: "fakeRolePerm description"
+ register: roleperm
+ check_mode: yes
+- name: verify results of update role permission in check mode
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+ - roleperm.name == "fakeRolePerm"
+ - roleperm.permission == "allow"
+ - roleperm.description == "fakeRolePerm description"
+
+- name: test update role permission
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ permission: deny
+ description: "fakeRolePerm description"
+ register: roleperm
+- name: verify results of update role permission
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+ - roleperm.name == "fakeRolePerm"
+ - roleperm.permission == "deny"
+ - roleperm.description == "fakeRolePerm description"
+
+- name: test update role permission idempotency
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ permission: deny
+ description: "fakeRolePerm description"
+ register: roleperm
+- name: verify results of update role permission idempotency
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is not changed
+ - roleperm.name == "fakeRolePerm"
+ - roleperm.permission == "deny"
+ - roleperm.description == "fakeRolePerm description"
+
+- name: test create a second role permission
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm2"
+ permission: allow
+ register: roleperm2
+- name: verify results of create a second role permission
+ assert:
+ that:
+ - roleperm2 is successful
+ - roleperm2 is changed
+ - roleperm2.name == "fakeRolePerm2"
+
+- name: test update rules order in check_mode
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ parent: "{{ roleperm2.id }}"
+ register: roleperm
+ check_mode: yes
+- name: verify results of update rule order check mode
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+ - roleperm.name == "fakeRolePerm"
+
+- name: test update rules order
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ parent: "{{ roleperm2.id }}"
+ register: roleperm
+- name: verify results of update rule order
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+ - roleperm.name == "fakeRolePerm"
+
+- name: test update rules order to the top of the list
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ parent: 0
+ register: roleperm
+- name: verify results of update rule order to the top of the list
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+ - roleperm.name == "fakeRolePerm"
+
+- name: test update rules order with parent NAME
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ parent: "{{ roleperm2.name }}"
+ register: roleperm
+- name: verify results of update rule order with parent NAME
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+ - roleperm.name == "fakeRolePerm"
+
+- name: test fail if permission AND parent args are present
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ permission: allow
+ parent: 0
+ register: roleperm
+ ignore_errors: true
+- name: verify results of fail if permission AND parent args are present
+ assert:
+ that:
+ - roleperm is failed
+ - 'roleperm.msg == "parameters are mutually exclusive: permission|parent"'
+
+- name: test fail if parent does not exist
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ parent: "badParent"
+ register: roleperm
+ ignore_errors: true
+- name: verify results of fail if parent does not exist
+ assert:
+ that:
+ - roleperm is failed
+ - roleperm.msg == "Parent rule 'badParent' not found"
+
+- name: test remove role permission in check_mode
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ state: absent
+ register: roleperm
+ check_mode: yes
+- name: verify results of rename role permission in check_mode
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+
+- name: test remove role permission
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm"
+ state: absent
+ register: roleperm
+- name: verify results of remove role permission
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
+
+- name: remove second role permission
+ cs_role_permission:
+ role: "{{ testRole.id }}"
+ name: "fakeRolePerm2"
+ state: absent
+ register: roleperm
+- name: verify results of remove second role permission
+ assert:
+ that:
+ - roleperm is successful
+ - roleperm is changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/tasks/main.yml
new file mode 100644
index 00000000..9adaa4de
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/tasks/main.yml
@@ -0,0 +1,183 @@
+---
+- name: setup network
+ cs_network:
+ name: "net_router"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: DefaultSharedNetworkOffering
+ network_domain: example.com
+ vlan: 1234
+ start_ip: 10.100.12.11
+ end_ip: 10.100.12.250
+ gateway: 10.100.12.1
+ netmask: 255.255.255.0
+ register: net
+- name: verify setup network
+ assert:
+ that:
+ - net is successful
+ - net.name == "net_router"
+
+- name: setup instance
+ cs_instance:
+ name: "instance-vm"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ network: "net_router"
+ state: started
+ register: instance
+- name: verify setup instance
+ assert:
+ that:
+ - instance is successful
+ - instance.name == "instance-vm"
+ - instance.state == "Running"
+
+- name: setup instance starts a router
+ cs_instance:
+ name: "instance-vm"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ network: "net_router"
+ state: started
+ register: instance
+- name: verify setup instance
+ assert:
+ that:
+ - instance is successful
+ - instance.name == "instance-vm"
+ - instance.state == "Running"
+
+- name: setup find the routers name
+ shell: cs listRouters listall=true networkid="{{ net.id }}" zone="{{ cs_common_zone_adv }}"
+ args:
+ chdir: "{{ playbook_dir }}"
+ register: router
+
+- debug:
+ var: router.stdout
+
+- set_fact:
+ router_json: "{{ router.stdout | from_json }}"
+
+- set_fact:
+ router_name: "{{ router_json.router[0].name }}"
+
+- name: test router started
+ cs_router:
+ name: "{{ router_name }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: started
+ register: router
+- name: verify test router started
+ assert:
+ that:
+ - router is successful
+
+- name: test stop router in check mode
+ cs_router:
+ name: "{{ router_name }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: stopped
+ check_mode: true
+ register: router
+- name: verify test stop router in check mode
+ assert:
+ that:
+ - router is changed
+ - router.state == "Running"
+ - router.service_offering == "System Offering For Software Router"
+
+- name: test stop router
+ cs_router:
+ name: "{{ router_name }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: stopped
+ register: router
+- name: verify test stop router
+ assert:
+ that:
+ - router is changed
+ - router.state == "Stopped"
+ - router.service_offering == "System Offering For Software Router"
+
+- name: test stop router idempotence
+ cs_router:
+ name: "{{ router_name }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: stopped
+ register: router
+- name: verify test stop router idempotence
+ assert:
+ that:
+ - router is not changed
+ - router.state == "Stopped"
+ - router.service_offering == "System Offering For Software Router"
+
+- name: test start router in check mode
+ cs_router:
+ name: "{{ router_name }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: started
+ register: router
+ check_mode: true
+- name: verify test start router in check mode
+ assert:
+ that:
+ - router is changed
+ - router.state == "Stopped"
+ - router.service_offering == "System Offering For Software Router"
+
+- name: test start router
+ cs_router:
+ name: "{{ router_name }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: started
+ register: router
+- name: verify test start router
+ assert:
+ that:
+ - router is changed
+ - router.state == "Running"
+ - router.service_offering == "System Offering For Software Router"
+
+- name: test start router idempotence
+ cs_router:
+ name: "{{ router_name }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: started
+ register: router
+- name: verify test start router idempotence
+ assert:
+ that:
+ - router is not changed
+ - router.state == "Running"
+ - router.service_offering == "System Offering For Software Router"
+
+- name: test restart router in check mode
+ cs_router:
+ name: "{{ router_name }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: restarted
+ register: router
+ check_mode: true
+- name: verify test restart router in check mode
+ assert:
+ that:
+ - router is changed
+ - router.state == "Running"
+ - router.service_offering == "System Offering For Software Router"
+
+- name: test restart router
+ cs_router:
+ name: "{{ router_name }}"
+ zone: "{{ cs_common_zone_adv }}"
+ state: restarted
+ register: router
+- name: verify test restart router
+ assert:
+ that:
+ - router is changed
+ - router.state == "Running"
+ - router.service_offering == "System Offering For Software Router"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/tasks/main.yml
new file mode 100644
index 00000000..1d32d280
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/tasks/main.yml
@@ -0,0 +1,79 @@
+---
+- name: setup
+ cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent
+ register: sg
+- name: verify setup
+ assert:
+ that:
+ - sg is successful
+
+- name: test fail if missing name
+ action: cs_securitygroup
+ register: sg
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - sg is failed
+ - "sg.msg == 'missing required arguments: name'"
+
+- name: test present security group in check mode
+ cs_securitygroup: name={{ cs_resource_prefix }}_sg
+ register: sg
+ check_mode: true
+- name: verify results of create security group in check mode
+ assert:
+ that:
+ - sg is successful
+ - sg is changed
+
+- name: test present security group
+ cs_securitygroup: name={{ cs_resource_prefix }}_sg
+ register: sg
+- name: verify results of create security group
+ assert:
+ that:
+ - sg is successful
+ - sg is changed
+ - sg.name == "{{ cs_resource_prefix }}_sg"
+
+- name: test present security group is idempotence
+ cs_securitygroup: name={{ cs_resource_prefix }}_sg
+ register: sg
+- name: verify results present security group is idempotence
+ assert:
+ that:
+ - sg is successful
+ - sg is not changed
+ - sg.name == "{{ cs_resource_prefix }}_sg"
+
+- name: test absent security group in check mode
+ cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent
+ register: sg
+ check_mode: true
+- name: verify results of absent security group in check mode
+ assert:
+ that:
+ - sg is successful
+ - sg is changed
+ - sg.name == "{{ cs_resource_prefix }}_sg"
+
+- name: test absent security group
+ cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent
+ register: sg
+- name: verify results of absent security group
+ assert:
+ that:
+ - sg is successful
+ - sg is changed
+ - sg.name == "{{ cs_resource_prefix }}_sg"
+
+- name: test absent security group is idempotence
+ cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent
+ register: sg
+- name: verify results of absent security group is idempotence
+ assert:
+ that:
+ - sg is successful
+ - sg is not changed
+ - sg.name is undefined
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/absent.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/absent.yml
new file mode 100644
index 00000000..8f1378e6
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/absent.yml
@@ -0,0 +1,171 @@
+---
+- name: test remove http range rule in check mode
+ cs_securitygroup_rule:
+ security_group: default
+ start_port: 8000
+ end_port: 8888
+ cidr: 1.2.3.4/32
+ state: absent
+ register: sg_rule
+ check_mode: true
+- name: verify create http range rule in check mode
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+ - sg_rule.type == 'ingress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.protocol == 'tcp'
+ - sg_rule.start_port == 8000
+ - sg_rule.end_port == 8888
+ - sg_rule.cidr == '1.2.3.4/32'
+
+- name: test remove http range rule
+ cs_securitygroup_rule:
+ security_group: default
+ start_port: 8000
+ end_port: 8888
+ cidr: 1.2.3.4/32
+ state: absent
+ register: sg_rule
+- name: verify create http range rule
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+ - sg_rule.type == 'ingress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.protocol == 'tcp'
+ - sg_rule.start_port == 8000
+ - sg_rule.end_port == 8888
+ - sg_rule.cidr == '1.2.3.4/32'
+
+- name: test remove http range rule idempotence
+ cs_securitygroup_rule:
+ security_group: default
+ start_port: 8000
+ end_port: 8888
+ cidr: 1.2.3.4/32
+ state: absent
+ register: sg_rule
+- name: verify create http range rule idempotence
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is not changed
+
+- name: test remove single port udp rule in check mode
+ cs_securitygroup_rule:
+ security_group: default
+ port: 5353
+ protocol: udp
+ type: egress
+ user_security_group: '{{ cs_resource_prefix }}_sg'
+ state: absent
+ register: sg_rule
+ check_mode: true
+- name: verify remove single port udp rule in check mode
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+ - sg_rule.type == 'egress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.protocol == 'udp'
+ - sg_rule.start_port == 5353
+ - sg_rule.end_port == 5353
+ - sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg'
+
+- name: test remove single port udp rule
+ cs_securitygroup_rule:
+ security_group: default
+ port: 5353
+ protocol: udp
+ type: egress
+ user_security_group: '{{ cs_resource_prefix }}_sg'
+ state: absent
+ register: sg_rule
+- name: verify remove single port udp rule
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+ - sg_rule.type == 'egress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.protocol == 'udp'
+ - sg_rule.start_port == 5353
+ - sg_rule.end_port == 5353
+ - sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg'
+
+- name: test remove single port udp rule idempotence
+ cs_securitygroup_rule:
+ security_group: default
+ port: 5353
+ protocol: udp
+ type: egress
+ user_security_group: '{{ cs_resource_prefix }}_sg'
+ state: absent
+ register: sg_rule
+- name: verify remove single port udp rule idempotence
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is not changed
+
+- name: test remove icmp rule in check mode
+ cs_securitygroup_rule:
+ security_group: default
+ protocol: icmp
+ type: ingress
+ icmp_type: -1
+ icmp_code: -1
+ state: absent
+ register: sg_rule
+ check_mode: true
+- name: verify icmp rule in check mode
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+ - sg_rule.type == 'ingress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.cidr == '0.0.0.0/0'
+ - sg_rule.protocol == 'icmp'
+ - sg_rule.icmp_code == -1
+ - sg_rule.icmp_type == -1
+
+- name: test remove icmp rule
+ cs_securitygroup_rule:
+ security_group: default
+ protocol: icmp
+ type: ingress
+ icmp_type: -1
+ icmp_code: -1
+ state: absent
+ register: sg_rule
+- name: verify icmp rule
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+ - sg_rule.type == 'ingress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.cidr == '0.0.0.0/0'
+ - sg_rule.protocol == 'icmp'
+ - sg_rule.icmp_code == -1
+ - sg_rule.icmp_type == -1
+
+- name: test remove icmp rule idempotence
+ cs_securitygroup_rule:
+ security_group: default
+ protocol: icmp
+ type: ingress
+ icmp_type: -1
+ icmp_code: -1
+ state: absent
+ register: sg_rule
+- name: verify icmp rule idempotence
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/cleanup.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/cleanup.yml
new file mode 100644
index 00000000..0fce5328
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/cleanup.yml
@@ -0,0 +1,7 @@
+- name: cleanup custom security group
+ cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent
+ register: sg
+- name: verify setup
+ assert:
+ that:
+ - sg is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/main.yml
new file mode 100644
index 00000000..e76745cb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/main.yml
@@ -0,0 +1,4 @@
+- include: setup.yml
+- include: present.yml
+- include: absent.yml
+- include: cleanup.yml
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/present.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/present.yml
new file mode 100644
index 00000000..a2a4e03c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/present.yml
@@ -0,0 +1,163 @@
+---
+- name: test create http range rule in check mode
+ cs_securitygroup_rule:
+ security_group: default
+ start_port: 8000
+ end_port: 8888
+ cidr: 1.2.3.4/32
+ register: sg_rule
+ check_mode: true
+- name: verify create http range rule in check mode
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+
+- name: test create http range rule
+ cs_securitygroup_rule:
+ security_group: default
+ start_port: 8000
+ end_port: 8888
+ cidr: 1.2.3.4/32
+ register: sg_rule
+- name: verify create http range rule
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+ - sg_rule.type == 'ingress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.protocol == 'tcp'
+ - sg_rule.start_port == 8000
+ - sg_rule.end_port == 8888
+ - sg_rule.cidr == '1.2.3.4/32'
+
+- name: test create http range rule idempotence
+ cs_securitygroup_rule:
+ security_group: default
+ start_port: 8000
+ end_port: 8888
+ cidr: 1.2.3.4/32
+ register: sg_rule
+- name: verify create http range rule idempotence
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is not changed
+ - sg_rule.type == 'ingress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.protocol == 'tcp'
+ - sg_rule.start_port == 8000
+ - sg_rule.end_port == 8888
+ - sg_rule.cidr == '1.2.3.4/32'
+
+- name: test create single port udp rule in check mode
+ cs_securitygroup_rule:
+ security_group: default
+ port: 5353
+ protocol: udp
+ type: egress
+ user_security_group: '{{ cs_resource_prefix }}_sg'
+ register: sg_rule
+ check_mode: true
+- name: verify create single port udp rule in check mode
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+
+- name: test create single port udp rule
+ cs_securitygroup_rule:
+ security_group: default
+ port: 5353
+ protocol: udp
+ type: egress
+ user_security_group: '{{ cs_resource_prefix }}_sg'
+ register: sg_rule
+- name: verify create single port udp rule
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+ - sg_rule.type == 'egress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.protocol == 'udp'
+ - sg_rule.start_port == 5353
+ - sg_rule.end_port == 5353
+ - sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg'
+
+
+- name: test single port udp rule idempotence
+ cs_securitygroup_rule:
+ security_group: default
+ port: 5353
+ protocol: udp
+ type: egress
+ user_security_group: '{{ cs_resource_prefix }}_sg'
+ register: sg_rule
+- name: verify single port udp rule idempotence
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is not changed
+ - sg_rule.type == 'egress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.protocol == 'udp'
+ - sg_rule.start_port == 5353
+ - sg_rule.end_port == 5353
+ - sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg'
+
+- name: test icmp rule in check mode
+ cs_securitygroup_rule:
+ security_group: default
+ protocol: icmp
+ type: ingress
+ icmp_type: -1
+ icmp_code: -1
+ register: sg_rule
+ check_mode: true
+- name: verify icmp rule in check mode
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+
+- name: test icmp rule
+ cs_securitygroup_rule:
+ security_group: default
+ protocol: icmp
+ type: ingress
+ icmp_type: -1
+ icmp_code: -1
+ register: sg_rule
+- name: verify icmp rule
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is changed
+ - sg_rule.type == 'ingress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.cidr == '0.0.0.0/0'
+ - sg_rule.protocol == 'icmp'
+ - sg_rule.icmp_code == -1
+ - sg_rule.icmp_type == -1
+
+- name: test icmp rule idempotence
+ cs_securitygroup_rule:
+ security_group: default
+ protocol: icmp
+ type: ingress
+ icmp_type: -1
+ icmp_code: -1
+ register: sg_rule
+- name: verify icmp rule idempotence
+ assert:
+ that:
+ - sg_rule is successful
+ - sg_rule is not changed
+ - sg_rule.type == 'ingress'
+ - sg_rule.security_group == 'default'
+ - sg_rule.cidr == '0.0.0.0/0'
+ - sg_rule.protocol == 'icmp'
+ - sg_rule.icmp_code == -1
+ - sg_rule.icmp_type == -1
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/setup.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/setup.yml
new file mode 100644
index 00000000..85625205
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/setup.yml
@@ -0,0 +1,56 @@
+- name: setup custom security group
+ cs_securitygroup: name={{ cs_resource_prefix }}_sg
+ register: sg
+- name: verify setup
+ assert:
+ that:
+ - sg is successful
+
+- name: setup default security group
+ cs_securitygroup: name=default
+ register: sg
+- name: verify setup
+ assert:
+ that:
+ - sg is successful
+
+- name: setup remove icmp rule
+ cs_securitygroup_rule:
+ security_group: default
+ protocol: icmp
+ type: ingress
+ icmp_type: -1
+ icmp_code: -1
+ state: absent
+ register: sg_rule
+- name: verify remove icmp rule
+ assert:
+ that:
+ - sg_rule is successful
+
+- name: setup remove http range rule
+ cs_securitygroup_rule:
+ security_group: default
+ start_port: 8000
+ end_port: 8888
+ cidr: 1.2.3.4/32
+ state: absent
+ register: sg_rule
+- name: verify remove http range rule
+ assert:
+ that:
+ - sg_rule is successful
+
+- name: setup remove single port udp rule
+ cs_securitygroup_rule:
+ security_group: default
+ port: 5353
+ protocol: udp
+ type: egress
+ user_security_group: '{{ cs_resource_prefix }}-user-sg'
+ state: absent
+ register: sg_rule
+- name: verify remove single port udp rule
+ assert:
+ that:
+ - sg_rule is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/guest_vm_service_offering.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/guest_vm_service_offering.yml
new file mode 100644
index 00000000..f7aee3c8
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/guest_vm_service_offering.yml
@@ -0,0 +1,223 @@
+---
+- name: setup service offering
+ cs_service_offering:
+ name: Micro
+ state: absent
+ register: so
+- name: verify setup service offering
+ assert:
+ that:
+ - so is successful
+
+- name: create service offering in check mode
+ cs_service_offering:
+ name: Micro
+ display_text: Micro 512mb 1cpu
+ cpu_number: 1
+ cpu_speed: 2198
+ memory: 512
+ host_tags: eco
+ storage_tags:
+ - eco
+ - backup
+ storage_type: local
+ register: so
+ check_mode: true
+- name: verify create service offering in check mode
+ assert:
+ that:
+ - so is changed
+
+- name: create service offering
+ cs_service_offering:
+ name: Micro
+ display_text: Micro 512mb 1cpu
+ cpu_number: 1
+ cpu_speed: 2198
+ memory: 512
+ host_tags: eco
+ storage_tags:
+ - eco
+ - backup
+ storage_type: local
+ register: so
+- name: verify create service offering
+ assert:
+ that:
+ - so is changed
+ - so.name == "Micro"
+ - so.display_text == "Micro 512mb 1cpu"
+ - so.cpu_number == 1
+ - so.cpu_speed == 2198
+ - so.memory == 512
+ - so.host_tags == ['eco']
+ - so.storage_tags == ['eco', 'backup']
+ - so.storage_type == "local"
+
+- name: create service offering idempotence
+ cs_service_offering:
+ name: Micro
+ display_text: Micro 512mb 1cpu
+ cpu_number: 1
+ cpu_speed: 2198
+ memory: 512
+ host_tags: eco
+ storage_tags:
+ - eco
+ - backup
+ storage_type: local
+ register: so
+- name: verify create service offering idempotence
+ assert:
+ that:
+ - so is not changed
+ - so.name == "Micro"
+ - so.display_text == "Micro 512mb 1cpu"
+ - so.cpu_number == 1
+ - so.cpu_speed == 2198
+ - so.memory == 512
+ - so.host_tags == ['eco']
+ - so.storage_tags == ['eco', 'backup']
+ - so.storage_type == "local"
+
+- name: update service offering in check mode
+ cs_service_offering:
+ name: Micro
+ display_text: Micro RAM 512MB 1vCPU
+ register: so
+ check_mode: true
+- name: verify create update offering in check mode
+ assert:
+ that:
+ - so is changed
+ - so.name == "Micro"
+ - so.display_text == "Micro 512mb 1cpu"
+ - so.cpu_number == 1
+ - so.cpu_speed == 2198
+ - so.memory == 512
+ - so.host_tags == ['eco']
+ - so.storage_tags == ['eco', 'backup']
+ - so.storage_type == "local"
+
+- name: update service offering
+ cs_service_offering:
+ name: Micro
+ display_text: Micro RAM 512MB 1vCPU
+ register: so
+- name: verify update service offerin
+ assert:
+ that:
+ - so is changed
+ - so.name == "Micro"
+ - so.display_text == "Micro RAM 512MB 1vCPU"
+ - so.cpu_number == 1
+ - so.cpu_speed == 2198
+ - so.memory == 512
+ - so.host_tags == ['eco']
+ - so.storage_tags == ['eco', 'backup']
+ - so.storage_type == "local"
+
+- name: update service offering idempotence
+ cs_service_offering:
+ name: Micro
+ display_text: Micro RAM 512MB 1vCPU
+ register: so
+- name: verify update service offering idempotence
+ assert:
+ that:
+ - so is not changed
+ - so.name == "Micro"
+ - so.display_text == "Micro RAM 512MB 1vCPU"
+ - so.cpu_number == 1
+ - so.cpu_speed == 2198
+ - so.memory == 512
+ - so.host_tags == ['eco']
+ - so.storage_tags == ['eco', 'backup']
+ - so.storage_type == "local"
+
+- name: remove service offering in check mode
+ cs_service_offering:
+ name: Micro
+ state: absent
+ check_mode: true
+ register: so
+- name: verify remove service offering in check mode
+ assert:
+ that:
+ - so is changed
+ - so.name == "Micro"
+ - so.display_text == "Micro RAM 512MB 1vCPU"
+ - so.cpu_number == 1
+ - so.cpu_speed == 2198
+ - so.memory == 512
+ - so.host_tags == ['eco']
+ - so.storage_tags == ['eco', 'backup']
+ - so.storage_type == "local"
+
+- name: remove service offering
+ cs_service_offering:
+ name: Micro
+ state: absent
+ register: so
+- name: verify remove service offering
+ assert:
+ that:
+ - so is changed
+ - so.name == "Micro"
+ - so.display_text == "Micro RAM 512MB 1vCPU"
+ - so.cpu_number == 1
+ - so.cpu_speed == 2198
+ - so.memory == 512
+ - so.host_tags == ['eco']
+ - so.storage_tags == ['eco', 'backup']
+ - so.storage_type == "local"
+
+- name: remove service offering idempotence
+ cs_service_offering:
+ name: Micro
+ state: absent
+ register: so
+- name: verify remove service offering idempotence
+ assert:
+ that:
+ - so is not changed
+
+- name: create custom service offering
+ cs_service_offering:
+ name: custom
+ display_text: custom offer
+ is_customized: yes
+ host_tags: eco
+ storage_tags:
+ - eco
+ - backup
+ storage_type: local
+ register: so
+- name: verify create custom service offering
+ assert:
+ that:
+ - so is changed
+ - so.name == "custom"
+ - so.display_text == "custom offer"
+ - so.is_customized == True
+ - so.cpu_number is not defined
+ - so.cpu_speed is not defined
+ - so.memory is not defined
+ - so.host_tags == ['eco']
+ - so.storage_tags == ['eco', 'backup']
+ - so.storage_type == "local"
+
+- name: remove custom service offering
+ cs_service_offering:
+ name: custom
+ state: absent
+ register: so
+- name: verify remove service offering
+ assert:
+ that:
+ - so is changed
+ - so.name == "custom"
+ - so.display_text == "custom offer"
+ - so.host_tags == ['eco']
+ - so.storage_tags == ['eco', 'backup']
+ - so.storage_type == "local"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/main.yml
new file mode 100644
index 00000000..581f7d74
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: guest_vm_service_offering.yml
+- import_tasks: system_vm_service_offering.yml \ No newline at end of file
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/system_vm_service_offering.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/system_vm_service_offering.yml
new file mode 100644
index 00000000..4c63a4b9
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/system_vm_service_offering.yml
@@ -0,0 +1,151 @@
+---
+- name: setup system offering
+ cs_service_offering:
+ name: System Offering for Ansible
+ is_system: true
+ state: absent
+ register: so
+- name: verify setup system offering
+ assert:
+ that:
+ - so is successful
+
+- name: fail missing storage type and is_system
+ cs_service_offering:
+ name: System Offering for Ansible
+ cpu_number: 1
+ cpu_speed: 500
+ memory: 512
+ host_tag: perf
+ storage_tag: perf
+ storage_type: shared
+ offer_ha: true
+ limit_cpu_usage: false
+ is_system: true
+ register: so
+ ignore_errors: true
+- name: verify create system service offering in check mode
+ assert:
+ that:
+ - so is failed
+ - so.msg.startswith('missing required arguments:')
+
+- name: create system service offering in check mode
+ cs_service_offering:
+ name: System Offering for Ansible
+ cpu_number: 1
+ cpu_speed: 500
+ memory: 512
+ host_tag: perf
+ storage_tag: perf
+ storage_type: shared
+ offer_ha: true
+ limit_cpu_usage: false
+ system_vm_type: domainrouter
+ is_system: true
+ register: so
+ check_mode: true
+- name: verify create system service offering in check mode
+ assert:
+ that:
+ - so is changed
+
+- name: create system service offering
+ cs_service_offering:
+ name: System Offering for Ansible
+ cpu_number: 1
+ cpu_speed: 500
+ memory: 512
+ host_tag: perf
+ storage_tag: perf
+ storage_type: shared
+ offer_ha: true
+ limit_cpu_usage: false
+ system_vm_type: domainrouter
+ is_system: true
+ register: so
+- name: verify create system service offering
+ assert:
+ that:
+ - so is changed
+ - so.name == "System Offering for Ansible"
+ - so.display_text == "System Offering for Ansible"
+ - so.cpu_number == 1
+ - so.cpu_speed == 500
+ - so.memory == 512
+ - so.host_tags == ['perf']
+ - so.storage_tags == ['perf']
+ - so.storage_type == "shared"
+ - so.offer_ha == true
+ - so.limit_cpu_usage == false
+ - so.system_vm_type == "domainrouter"
+ - so.is_system == true
+
+- name: create system service offering idempotence
+ cs_service_offering:
+ name: System Offering for Ansible
+ cpu_number: 1
+ cpu_speed: 500
+ memory: 512
+ host_tag: perf
+ storage_tag: perf
+ storage_type: shared
+ offer_ha: true
+ limit_cpu_usage: false
+ system_vm_type: domainrouter
+ is_system: true
+ register: so
+- name: verify create system service offering idempotence
+ assert:
+ that:
+ - so is not changed
+ - so.name == "System Offering for Ansible"
+ - so.display_text == "System Offering for Ansible"
+ - so.cpu_number == 1
+ - so.cpu_speed == 500
+ - so.memory == 512
+ - so.host_tags == ['perf']
+ - so.storage_tags == ['perf']
+ - so.storage_type == "shared"
+ - so.offer_ha == true
+ - so.limit_cpu_usage == false
+ - so.system_vm_type == "domainrouter"
+ - so.is_system == true
+
+- name: remove system service offering in check mode
+ cs_service_offering:
+ name: System Offering for Ansible
+ is_system: true
+ state: absent
+ check_mode: true
+ register: so
+- name: verify remove system service offering in check mode
+ assert:
+ that:
+ - so is changed
+ - so.name == "System Offering for Ansible"
+ - so.is_system == true
+
+- name: remove system service offering
+ cs_service_offering:
+ name: System Offering for Ansible
+ is_system: true
+ state: absent
+ register: so
+- name: verify remove system service offering
+ assert:
+ that:
+ - so is changed
+ - so.name == "System Offering for Ansible"
+ - so.is_system == true
+
+- name: remove system service offering idempotence
+ cs_service_offering:
+ name: System Offering for Ansible
+ is_system: true
+ state: absent
+ register: so
+- name: verify remove system service offering idempotence
+ assert:
+ that:
+ - so is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/tasks/main.yml
new file mode 100644
index 00000000..d5ba1bdc
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/tasks/main.yml
@@ -0,0 +1,176 @@
+---
+- name: setup instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ register: instance
+- name: verify setup instance
+ assert:
+ that:
+ - instance is successful
+
+- name: setup snapshot policy absent
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ state: absent
+ register: snapshot
+- name: verify setup snapshot policy absent
+ assert:
+ that:
+ - snapshot is successful
+
+- name: create snapshot policy in check mode
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ schedule: 5
+ check_mode: true
+ register: snapshot
+- name: verify create snapshot policy in check mode
+ assert:
+ that:
+ - snapshot is changed
+
+- name: create snapshot policy
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ schedule: 5
+ register: snapshot
+- name: verify create snapshot policy
+ assert:
+ that:
+ - snapshot is changed
+ - snapshot.schedule == "5"
+ - snapshot.interval_type == "hourly"
+ - snapshot.volume != ""
+
+- name: create snapshot policy idempotence
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ schedule: 5
+ register: snapshot
+- name: verify create snapshot policy idempotence
+ assert:
+ that:
+ - snapshot is not changed
+ - snapshot.schedule == "5"
+ - snapshot.interval_type == "hourly"
+ - snapshot.volume != ""
+
+- name: update snapshot policy
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ schedule: 6
+ check_mode: true
+ register: snapshot
+- name: verify update snapshot policy
+ assert:
+ that:
+ - snapshot is changed
+ - snapshot.schedule == "5"
+ - snapshot.interval_type == "hourly"
+ - snapshot.volume != ""
+
+- name: update snapshot policy in check mode
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ schedule: 6
+ max_snaps: 3
+ time_zone: "Europe/Zurich"
+ check_mode: true
+ register: snapshot
+- name: verify update snapshot policy in check mode
+ assert:
+ that:
+ - snapshot is changed
+ - snapshot.schedule == "5"
+ - snapshot.interval_type == "hourly"
+ - snapshot.volume != ""
+ - snapshot.max_snaps == 8
+ - snapshot.time_zone == "UTC"
+
+- name: update snapshot policy
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ schedule: 6
+ max_snaps: 3
+ time_zone: "Europe/Zurich"
+ register: snapshot
+- name: verify update snapshot policy
+ assert:
+ that:
+ - snapshot is changed
+ - snapshot.schedule == "6"
+ - snapshot.interval_type == "hourly"
+ - snapshot.volume != ""
+ - snapshot.max_snaps == 3
+ - snapshot.time_zone == "Europe/Zurich"
+
+- name: update snapshot policy idempotence
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ schedule: 6
+ max_snaps: 3
+ time_zone: "Europe/Zurich"
+ register: snapshot
+- name: verify update snapshot policy idempotence
+ assert:
+ that:
+ - snapshot is not changed
+ - snapshot.schedule == "6"
+ - snapshot.interval_type == "hourly"
+ - snapshot.volume != ""
+ - snapshot.max_snaps == 3
+ - snapshot.time_zone == "Europe/Zurich"
+
+- name: remove snapshot policy in check mode
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ state: absent
+ check_mode: true
+ register: snapshot
+- name: verify remove snapshot policy in check mode
+ assert:
+ that:
+ - snapshot is changed
+ - snapshot.schedule == "6"
+ - snapshot.interval_type == "hourly"
+ - snapshot.volume != ""
+ - snapshot.max_snaps == 3
+ - snapshot.time_zone == "Europe/Zurich"
+
+- name: remove snapshot policy
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ state: absent
+ register: snapshot
+- name: verify remove snapshot policy
+ assert:
+ that:
+ - snapshot is changed
+ - snapshot.schedule == "6"
+ - snapshot.interval_type == "hourly"
+ - snapshot.volume != ""
+ - snapshot.max_snaps == 3
+ - snapshot.time_zone == "Europe/Zurich"
+
+- name: remove snapshot policy idempotence
+ cs_snapshot_policy:
+ vm: "{{ cs_resource_prefix }}-vm-snapshot-policy"
+ interval_type: hourly
+ state: absent
+ register: snapshot
+- name: verify remove snapshot policy idempotence
+ assert:
+ that:
+ - snapshot is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/tasks/main.yml
new file mode 100644
index 00000000..89aa2522
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/tasks/main.yml
@@ -0,0 +1,197 @@
+---
+- name: setup cleanup
+ cs_sshkeypair:
+ name: "{{ item }}"
+ state: absent
+ register: sshkey
+ with_items:
+ - first-sshkey
+ - first-sshkey-renamed
+ - second-sshkey
+- name: verify setup cleanup
+ assert:
+ that:
+ - sshkey is success
+
+- name: test fail on missing name
+ action: cs_sshkeypair
+ ignore_errors: true
+ register: sshkey
+- name: verify results of fail on missing name
+ assert:
+ that:
+ - sshkey is failed
+ - "sshkey.msg == 'missing required arguments: name'"
+
+- name: test ssh key creation in check mode
+ cs_sshkeypair:
+ name: first-sshkey
+ register: sshkey
+ check_mode: true
+- name: verify results of ssh key creation in check mode
+ assert:
+ that:
+ - sshkey is successful
+ - sshkey is changed
+
+- name: test ssh key creation
+ cs_sshkeypair:
+ name: first-sshkey
+ register: sshkey
+- name: verify results of ssh key creation
+ assert:
+ that:
+ - sshkey is successful
+ - sshkey is changed
+ - sshkey.fingerprint is defined and sshkey.fingerprint != ""
+ - sshkey.private_key is defined and sshkey.private_key != ""
+ - sshkey.name == "first-sshkey"
+
+- name: test ssh key creation idempotence
+ cs_sshkeypair:
+ name: first-sshkey
+ register: sshkey2
+- name: verify results of ssh key creation idempotence
+ assert:
+ that:
+ - sshkey2 is successful
+ - sshkey2 is not changed
+ - sshkey2.fingerprint is defined and sshkey2.fingerprint == sshkey.fingerprint
+ - sshkey2.private_key is not defined
+ - sshkey2.name == "first-sshkey"
+
+- name: test replace ssh public key in check mode
+ cs_sshkeypair:
+ name: first-sshkey
+ public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+ register: sshkey2
+ check_mode: true
+- name: verify results of replace ssh public key in check mode
+ assert:
+ that:
+ - sshkey2 is successful
+ - sshkey2 is changed
+ - sshkey2.fingerprint is defined and sshkey2.fingerprint == sshkey.fingerprint
+ - sshkey2.private_key is not defined
+ - sshkey2.name == "first-sshkey"
+
+- name: test replace ssh public key
+ cs_sshkeypair:
+ name: first-sshkey
+ public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+ register: sshkey3
+- name: verify results of replace ssh public key
+ assert:
+ that:
+ - sshkey3 is changed
+ - sshkey3.fingerprint is defined and sshkey3.fingerprint != sshkey2.fingerprint
+ - sshkey3.private_key is not defined
+ - sshkey3.name == "first-sshkey"
+
+- name: test replace ssh public key idempotence
+ cs_sshkeypair:
+ name: first-sshkey
+ public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+ register: sshkey4
+- name: verify results of ssh public key idempotence
+ assert:
+ that:
+ - sshkey4 is not changed
+ - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint
+ - sshkey4.private_key is not defined
+ - sshkey4.name == "first-sshkey"
+
+- name: test rename ssh key in check mode
+ cs_sshkeypair:
+ name: first-sshkey-renamed
+ public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+ register: sshkey4
+ check_mode: true
+- name: verify test rename ssh key in check mode
+ assert:
+ that:
+ - sshkey4 is changed
+ - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint
+ - sshkey4.private_key is not defined
+ - sshkey4.name == "first-sshkey"
+
+- name: test rename ssh key
+ cs_sshkeypair:
+ name: first-sshkey-renamed
+ public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+ register: sshkey4
+- name: verify test rename ssh key
+ assert:
+ that:
+ - sshkey4 is changed
+ - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint
+ - sshkey4.private_key is not defined
+ - sshkey4.name == "first-sshkey-renamed"
+
+- name: test rename ssh key idempotence
+ cs_sshkeypair:
+ name: first-sshkey-renamed
+ public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+ register: sshkey4
+- name: verify test rename ssh key idempotence
+ assert:
+ that:
+ - sshkey4 is not changed
+ - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint
+ - sshkey4.private_key is not defined
+ - sshkey4.name == "first-sshkey-renamed"
+
+- name: setup ssh key with name "second-sshkey"
+ cs_sshkeypair:
+ name: second-sshkey
+
+- name: test different but exisitng name but same ssh public key as first-sshkey
+ cs_sshkeypair:
+ name: second-sshkey
+ public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+ register: sshkey
+- name: verify test different but exisitng name but same ssh public key as first-sshkey
+ assert:
+ that:
+ - sshkey is changed
+ - sshkey.fingerprint is defined and sshkey.fingerprint == sshkey4.fingerprint
+ - sshkey.private_key is not defined
+ - sshkey.name == "second-sshkey"
+
+- name: test ssh key absent in check mode
+ cs_sshkeypair: name=second-sshkey state=absent
+ register: sshkey5
+ check_mode: true
+- name: verify result of key absent in check mode
+ assert:
+ that:
+ - sshkey5 is changed
+ - sshkey5.fingerprint is defined and sshkey5.fingerprint == sshkey3.fingerprint
+ - sshkey5.private_key is not defined
+ - sshkey5.name == "second-sshkey"
+
+- name: test ssh key absent
+ cs_sshkeypair:
+ name: second-sshkey
+ state: absent
+ register: sshkey5
+- name: verify result of key absent
+ assert:
+ that:
+ - sshkey5 is changed
+ - sshkey5.fingerprint is defined and sshkey5.fingerprint == sshkey3.fingerprint
+ - sshkey5.private_key is not defined
+ - sshkey5.name == "second-sshkey"
+
+- name: test ssh key absent idempotence
+ cs_sshkeypair:
+ name: second-sshkey
+ state: absent
+ register: sshkey6
+- name: verify result of ssh key absent idempotence
+ assert:
+ that:
+ - sshkey6 is not changed
+ - sshkey6.fingerprint is not defined
+ - sshkey6.private_key is not defined
+ - sshkey6.name is not defined
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/tasks/main.yml
new file mode 100644
index 00000000..a418b984
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/tasks/main.yml
@@ -0,0 +1,465 @@
+---
+- name: setup host is present
+ cs_host:
+ name: sim
+ url: "http://sim/c0-basic/h2"
+ cluster: C0-adv
+ pod: POD0-adv
+ username: root
+ password: password
+ hypervisor: Simulator
+ allocation_state: enabled
+ zone: "{{ cs_common_zone_adv }}"
+ register: host
+- name: verify setup host is present
+ assert:
+ that:
+ - host is successful
+
+- name: setup storage pool is absent
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sp
+- name: verify setup storage pool is absent
+ assert:
+ that:
+ - sp is successful
+
+- name: test fail if missing params
+ cs_storage_pool:
+ register: sp
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - sp is failed
+ - "sp.msg == 'missing required arguments: name'"
+
+- name: test fail if provider unknown
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ provider: DNE
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ register: sp
+ ignore_errors: true
+- name: verify test fail if provider unknown
+ assert:
+ that:
+ - sp is failed
+ - "sp.msg == 'Storage provider DNE not found'"
+
+- name: test fail if cluster unknown
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: DNE
+ pod: POD0-adv
+ register: sp
+ ignore_errors: true
+- name: verify test fail if cluster unknown
+ assert:
+ that:
+ - sp is failed
+ - "sp.msg == 'Cluster DNE not found'"
+
+- name: test fail if pod unknown
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: DNE
+ register: sp
+ ignore_errors: true
+- name: verify test fail if pod unknown
+ assert:
+ that:
+ - sp is failed
+ - "'Pod DNE not found' in sp.msg"
+
+- name: create storage pool in check mode
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ register: sp
+ check_mode: true
+- name: verify create storage pool in check mode
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+
+- name: create storage pool
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ register: sp
+- name: verify create storage pool
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: create storage pool idempotence
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ cluster: C0-adv
+ pod: POD0-adv
+ register: sp
+- name: verify create storage pool idempotence
+ assert:
+ that:
+ - sp is successful
+ - sp is not changed
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: disable storage pool in check mode
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ cluster: C0-adv
+ pod: POD0-adv
+ allocation_state: disabled
+ check_mode: true
+ register: sp
+- name: verify disable storage pool in check mode
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'enabled'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: disable storage pool
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ allocation_state: disabled
+ register: sp
+- name: verify disable storage pool
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'disabled'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: disable storage pool idempotence
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ allocation_state: disabled
+ register: sp
+- name: verify disable storage pool idempotence
+ assert:
+ that:
+ - sp is successful
+ - sp is not changed
+ - sp.allocation_state == 'disabled'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: update while storage pool disabled in check mode
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ storage_tags:
+ - eco
+ - ssd
+ check_mode: true
+ register: sp
+- name: verify update while storage pool disabled in check mode
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'disabled'
+ - sp.storage_tags == []
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: update while storage pool disabled
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ storage_tags:
+ - eco
+ - ssd
+ register: sp
+- name: verify update while storage pool disabled
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'disabled'
+ - sp.storage_tags == ['eco', 'ssd']
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: update while storage pool disabled idempotence
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ storage_tags:
+ - eco
+ - ssd
+ register: sp
+- name: verify update while storage pool disabled idempotence
+ assert:
+ that:
+ - sp is successful
+ - sp is not changed
+ - sp.allocation_state == 'disabled'
+ - sp.storage_tags == ['eco', 'ssd']
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: put storage in maintenance pool in check mode
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ allocation_state: maintenance
+ check_mode: true
+ register: sp
+- name: verify put storage in maintenance pool in check mode
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'disabled'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: put storage in maintenance pool
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ allocation_state: maintenance
+ register: sp
+- name: verify put storage in maintenance pool
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'maintenance'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: put storage in maintenance pool idempotence
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ allocation_state: maintenance
+ register: sp
+- name: verify put storage in maintenance pool idempotence
+ assert:
+ that:
+ - sp is successful
+ - sp is not changed
+ - sp.allocation_state == 'maintenance'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: update while in maintenance pool
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ storage_tag: perf
+ register: sp
+- name: verify update while in maintenance pool
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'maintenance'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+ - sp.storage_tags == ['perf']
+
+- name: remove storage pool in check mode
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sp
+ check_mode: true
+- name: verify remove storage pool in check mode
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: remove storage pool
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sp
+- name: verify remove storage pool
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: remove storage pool idempotence
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sp
+- name: verify remove storage pool idempotence
+ assert:
+ that:
+ - sp is successful
+ - sp is not changed
+
+- name: create storage pool in maintenance
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ allocation_state: maintenance
+ register: sp
+- name: verify create storage pool in maintenance
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'maintenance'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: remove storage pool in maintenance
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sp
+- name: verify storage pool in maintenance
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'maintenance'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: create storage pool disabled
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname
+ scope: cluster
+ cluster: C0-adv
+ pod: POD0-adv
+ allocation_state: disabled
+ register: sp
+- name: verify create storage pool in disabled
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'disabled'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
+
+- name: verify remove disabled storag e pool
+ cs_storage_pool:
+ name: "storage_pool_adv"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: sp
+- name: verify remove disabled storage pool
+ assert:
+ that:
+ - sp is successful
+ - sp is changed
+ - sp.allocation_state == 'disabled'
+ - sp.cluster == "C0-adv"
+ - sp.pod == "POD0-adv"
+ - sp.storage_url == "RBD://ceph-mons.domain/poolname"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/defaults/main.yml
new file mode 100644
index 00000000..80f67305
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+cs_template_hypervisor: Simulator
+cs_template_os_type: Other Linux (64-bit)
+cs_template_url: http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-vmware.ova
+cs_template_format: OVA
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/main.yml
new file mode 100644
index 00000000..ffeaa8a0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: test1.yml
+- import_tasks: test2.yml
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test1.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test1.yml
new file mode 100644
index 00000000..755394fa
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test1.yml
@@ -0,0 +1,160 @@
+---
+- name: setup template
+ cs_template:
+ name: "ansible-template-test1"
+ state: absent
+ register: template
+- name: verify setup template
+ assert:
+ that:
+ - template is successful
+
+- name: test download template in check mode
+ cs_template:
+ name: "ansible-template-test1"
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ cross_zones: yes
+ register: template
+ check_mode: yes
+- name: verify test download template in check mode
+ assert:
+ that:
+ - template is changed
+
+- name: test download template
+ cs_template:
+ name: "ansible-template-test1"
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ cross_zones: yes
+ register: template
+- name: verify test download template
+ assert:
+ that:
+ - template is changed
+ - template.name == "ansible-template-test1"
+ - template.display_text == "ansible-template-test1"
+ - template.cross_zones == true
+
+- name: test download template idempotence
+ cs_template:
+ name: "ansible-template-test1"
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ cross_zones: yes
+ register: template
+- name: verify test download template idempotence
+ assert:
+ that:
+ - template is not changed
+ - template.name == "ansible-template-test1"
+ - template.display_text == "ansible-template-test1"
+ - template.cross_zones == true
+
+- name: test update template in check mode
+ cs_template:
+ name: "ansible-template-test1"
+ display_text: "{{ cs_resource_prefix }}-template display_text"
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ is_featured: yes
+ cross_zones: yes
+ register: template
+ check_mode: yes
+- name: verify test update template in check mode
+ assert:
+ that:
+ - template is changed
+ - template.name == "ansible-template-test1"
+ - template.display_text == "ansible-template-test1"
+ - template.cross_zones == true
+ - template.is_featured == false
+
+- name: test update template
+ cs_template:
+ name: "ansible-template-test1"
+ display_text: "{{ cs_resource_prefix }}-template display_text"
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ is_featured: yes
+ cross_zones: yes
+ register: template
+- name: verify test update template
+ assert:
+ that:
+ - template is changed
+ - template.name == "ansible-template-test1"
+ - template.display_text == "{{ cs_resource_prefix }}-template display_text"
+ - template.cross_zones == true
+ - template.is_featured == true
+
+- name: test update template idempotence
+ cs_template:
+ name: "ansible-template-test1"
+ display_text: "{{ cs_resource_prefix }}-template display_text"
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ is_featured: yes
+ cross_zones: yes
+ register: template
+- name: verify test update template idempotence
+ assert:
+ that:
+ - template is not changed
+ - template.name == "ansible-template-test1"
+ - template.display_text == "{{ cs_resource_prefix }}-template display_text"
+ - template.cross_zones == true
+ - template.is_featured == true
+
+- name: test remove template in check mode
+ cs_template:
+ name: "ansible-template-test1"
+ state: absent
+ cross_zones: yes
+ register: template
+ check_mode: yes
+- name: verify test remove template in check mode
+ assert:
+ that:
+ - template is changed
+ - template.name == "ansible-template-test1"
+ - template.display_text == "{{ cs_resource_prefix }}-template display_text"
+ - template.cross_zones == true
+
+- name: test remove template
+ cs_template:
+ name: "ansible-template-test1"
+ state: absent
+ cross_zones: yes
+ register: template
+- name: verify test remove template
+ assert:
+ that:
+ - template is changed
+ - template.name == "ansible-template-test1"
+ - template.display_text == "{{ cs_resource_prefix }}-template display_text"
+ - template.cross_zones == true
+
+- name: test remove template idempotence
+ cs_template:
+ name: "ansible-template-test1"
+ state: absent
+ cross_zones: yes
+ register: template
+- name: verify test remove template idempotence
+ assert:
+ that:
+ - template is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test2.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test2.yml
new file mode 100644
index 00000000..d5d44453
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test2.yml
@@ -0,0 +1,181 @@
+---
+- name: setup template first template
+ cs_template:
+ name: ansible-template-test2
+ display_text: first template
+ state: absent
+ cross_zones: yes
+ template_find_options: display_text
+ register: template
+- name: verify setup template first template
+ assert:
+ that:
+ - template is successful
+
+- name: setup template second template
+ cs_template:
+ name: ansible-template-test2
+ display_text: second template
+ state: absent
+ cross_zones: yes
+ template_find_options: display_text
+ register: template
+- name: verify setup template second template
+ assert:
+ that:
+ - template is successful
+
+- name: test register first template
+ cs_template:
+ name: ansible-template-test2
+ display_text: first template
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ cross_zones: yes
+ template_find_options: display_text
+ register: template_first
+- name: verify test register first template
+ assert:
+ that:
+ - template_first is changed
+ - template_first.name == "ansible-template-test2"
+ - template_first.display_text == "first template"
+ - template_first.cross_zones == true
+
+- name: test register second template
+ cs_template:
+ name: ansible-template-test2
+ display_text: second template
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ cross_zones: yes
+ template_find_options: display_text
+ register: template_second
+- name: verify test register second template
+ assert:
+ that:
+ - template_second is changed
+ - template_second.name == "ansible-template-test2"
+ - template_second.display_text == "second template"
+ - template_second.cross_zones == true
+ - template_second.id != template_first.id
+
+- name: test multiple template same name absent without find options
+ cs_template:
+ name: ansible-template-test2
+ state: absent
+ cross_zones: yes
+ register: template
+ ignore_errors: yes
+- name: verify test multiple template same name absent without find options
+ assert:
+ that:
+ - template is failed
+ - template.msg.startswith('Multiple templates found')
+
+- name: test update second template
+ cs_template:
+ name: ansible-template-test2
+ display_text: second template
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ is_featured: yes
+ is_public: yes
+ cross_zones: yes
+ template_find_options: display_text
+ register: template
+- name: verify test update second template
+ assert:
+ that:
+ - template is changed
+ - template.name == "ansible-template-test2"
+ - template.display_text == "second template"
+ - template.cross_zones == true
+ - template.id == template_second.id
+ - template.is_featured == true
+ - template.is_public == true
+
+- name: test update second template idempotence
+ cs_template:
+ name: ansible-template-test2
+ display_text: second template
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ is_featured: yes
+ is_public: yes
+ cross_zones: yes
+ template_find_options: display_text
+ register: template
+- name: verify test update second template idempotence
+ assert:
+ that:
+ - template is not changed
+ - template.name == "ansible-template-test2"
+ - template.display_text == "second template"
+ - template.cross_zones == true
+ - template.id == template_second.id
+ - template.is_featured == true
+
+- name: test update second template idempotence 2
+ cs_template:
+ name: ansible-template-test2
+ display_text: second template
+ url: "{{ cs_template_url }}"
+ format: "{{ cs_template_format }}"
+ hypervisor: "{{ cs_template_hypervisor }}"
+ os_type: "{{ cs_template_os_type }}"
+ cross_zones: yes
+ template_find_options: display_text
+ register: template
+- name: verify test update second template idempotence
+ assert:
+ that:
+ - template is not changed
+ - template.name == "ansible-template-test2"
+ - template.display_text == "second template"
+ - template.cross_zones == true
+ - template.id == template_second.id
+
+- name: test delete first template
+ cs_template:
+ name: ansible-template-test2
+ display_text: first template
+ state: absent
+ cross_zones: yes
+ template_find_options: display_text
+ register: template
+- name: verify test delete first template
+ assert:
+ that:
+ - template is changed
+ - template.name == "ansible-template-test2"
+ - template.display_text == "first template"
+ - template.cross_zones == true
+ - template.id == template_first.id
+ - template.is_featured == false
+
+- name: test delete second template
+ cs_template:
+ name: ansible-template-test2
+ display_text: second template
+ state: absent
+ cross_zones: yes
+ template_find_options: display_text
+ register: template
+- name: verify test delete second template
+ assert:
+ that:
+ - template is changed
+ - template.name == "ansible-template-test2"
+ - template.display_text == "second template"
+ - template.cross_zones == true
+ - template.id == template_second.id
+ - template.is_featured == true
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/tasks/main.yml
new file mode 100644
index 00000000..76d42054
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/tasks/main.yml
@@ -0,0 +1,174 @@
+---
+# Create a new zone - the default one is enabled
+- name: assure zone for tests
+ cs_zone:
+ name: cs-test-zone
+ state: present
+ dns1: 8.8.8.8
+ network_type: Advanced
+ register: cszone
+
+- name: ensure the zone is disabled
+ cs_zone:
+ name: "{{ cszone.name }}"
+ state: disabled
+ register: cszone
+
+- name: setup a network
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ isolation_method: VLAN
+ broadcast_domain_range: ZONE
+ ignore_errors: true
+ register: pn
+
+
+- name: fail on missing params
+ cs_traffic_type:
+ zone: "{{ pn.zone }}"
+ ignore_errors: true
+ register: tt
+- name: validate fail on missing params
+ assert:
+ that:
+ - tt is failed
+ - 'tt.msg == "missing required arguments: physical_network, traffic_type"'
+
+- name: add a traffic type in check mode
+ cs_traffic_type:
+ physical_network: "{{ pn.name }}"
+ traffic_type: Guest
+ zone: "{{ pn.zone }}"
+ register: tt
+ check_mode: yes
+- name: validate add a traffic type in check mode
+ assert:
+ that:
+ - tt is changed
+ - tt.zone == pn.zone
+
+- name: add a traffic type
+ cs_traffic_type:
+ physical_network: "{{ pn.name }}"
+ traffic_type: Guest
+ zone: "{{ pn.zone }}"
+ register: tt
+- name: validate add a traffic type
+ assert:
+ that:
+ - tt is changed
+ - tt.physical_network == pn.id
+ - tt.traffic_type == 'Guest'
+ - tt.zone == pn.zone
+
+- name: add a traffic type idempotence
+ cs_traffic_type:
+ physical_network: "{{ pn.name }}"
+ traffic_type: Guest
+ zone: "{{ pn.zone }}"
+ register: tt
+- name: validate add a traffic type idempotence
+ assert:
+ that:
+ - tt is not changed
+ - tt.physical_network == pn.id
+ - tt.traffic_type == 'Guest'
+ - tt.zone == pn.zone
+
+- name: update traffic type
+ cs_traffic_type:
+ physical_network: "{{ pn.name }}"
+ traffic_type: Guest
+ kvm_networklabel: cloudbr0
+ zone: "{{ pn.zone }}"
+ register: tt
+- name: validate update traffic type
+ assert:
+ that:
+ - tt is changed
+ - tt.physical_network == pn.id
+ - tt.traffic_type == 'Guest'
+ - tt.zone == pn.zone
+ - tt.kvm_networklabel == 'cloudbr0'
+
+- name: update traffic type idempotence
+ cs_traffic_type:
+ physical_network: "{{ pn.name }}"
+ traffic_type: Guest
+ kvm_networklabel: cloudbr0
+ zone: "{{ pn.zone }}"
+ register: tt
+- name: validate update traffic type idempotence
+ assert:
+ that:
+ - tt is not changed
+ - tt.physical_network == pn.id
+ - tt.traffic_type == 'Guest'
+ - tt.zone == pn.zone
+ - tt.kvm_networklabel == 'cloudbr0'
+
+- name: add a removable traffic type
+ cs_traffic_type:
+ physical_network: "{{ pn.name }}"
+ traffic_type: Public
+ kvm_networklabel: cloudbr1
+ zone: "{{ pn.zone }}"
+ register: tt
+- name: validate add a removable traffic type
+ assert:
+ that:
+ - tt is changed
+ - tt.physical_network == pn.id
+ - tt.traffic_type == 'Public'
+ - tt.zone == pn.zone
+ - tt.kvm_networklabel == 'cloudbr1'
+
+- name: remove traffic type in check mode
+ cs_traffic_type:
+ physical_network: "{{ pn.name }}"
+ traffic_type: Public
+ state: absent
+ zone: "{{ pn.zone }}"
+ check_mode: yes
+ register: tt
+- name: validate remove traffic type in check mode
+ assert:
+ that:
+ - tt is changed
+
+- name: remove traffic type
+ cs_traffic_type:
+ physical_network: "{{ pn.name }}"
+ traffic_type: Public
+ state: absent
+ zone: "{{ pn.zone }}"
+ register: tt
+- name: validate remove traffic type
+ assert:
+ that:
+ - tt is changed
+ - tt.zone == pn.zone
+
+- name: remove traffic type idempotence
+ cs_traffic_type:
+ physical_network: "{{ pn.name }}"
+ traffic_type: Public
+ state: absent
+ zone: "{{ pn.zone }}"
+ register: tt
+- name: validate
+ assert:
+ that:
+ - tt is not changed
+ - tt.zone == pn.zone
+
+- name: cleanup
+ block:
+ - cs_physical_network:
+ name: "{{ pn.name }}"
+ zone: "{{ cszone.name }}"
+ state: absent
+ - cs_zone:
+ name: "{{ cszone.name }}"
+ state: absent
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/tasks/main.yml
new file mode 100644
index 00000000..f48588da
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/tasks/main.yml
@@ -0,0 +1,618 @@
+---
+- name: setup
+ cs_user: username={{ cs_resource_prefix }}_user state=absent
+ register: user
+- name: verify setup
+ assert:
+ that:
+ - user is successful
+
+- name: test fail if missing username
+ action: cs_user
+ register: user
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - user is failed
+ - 'user.msg == "missing required arguments: username"'
+
+- name: test fail if missing params if state=present
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ register: user
+ ignore_errors: true
+- name: verify results of fail if missing params if state=present
+ assert:
+ that:
+ - user is failed
+ - 'user.msg == "missing required arguments: account, email, password, first_name, last_name"'
+
+- name: test create user in check mode
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ account: "admin"
+ register: user
+ check_mode: true
+- name: verify results of create user in check mode
+ assert:
+ that:
+ - user is successful
+ - user is changed
+
+- name: test create user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ account: "admin"
+ register: user
+- name: verify results of create user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name"
+ - user.email == "{{ cs_resource_prefix }}@example.com"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+ - user.user_api_key is not defined
+
+- name: test create user idempotence
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ account: "admin"
+ register: user
+- name: verify results of create user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is not changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name"
+ - user.email == "{{ cs_resource_prefix }}@example.com"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+ - user.user_api_key is not defined
+
+- name: test create account
+ cs_account:
+ name: "{{ cs_resource_prefix }}_acc"
+ username: "{{ cs_resource_prefix }}_acc_username"
+ password: "{{ cs_resource_prefix }}_acc_password"
+ last_name: "{{ cs_resource_prefix }}_acc_last_name"
+ first_name: "{{ cs_resource_prefix }}_acc_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ network_domain: "example.com"
+ register: acc
+- name: verify results of create account
+ assert:
+ that:
+ - acc is successful
+ - acc is changed
+ - acc.name == "{{ cs_resource_prefix }}_acc"
+ - acc.network_domain == "example.com"
+ - acc.account_type == "user"
+ - acc.state == "enabled"
+ - acc.domain == "ROOT"
+ - acc is changed
+
+- name: test create user2 in check mode
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user2"
+ password: "{{ cs_resource_prefix }}_password2"
+ last_name: "{{ cs_resource_prefix }}_last_name2"
+ first_name: "{{ cs_resource_prefix }}_first_name2"
+ email: "{{ cs_resource_prefix }}@example2.com"
+ account: "{{ cs_resource_prefix }}_acc"
+ keys_registered: true
+ check_mode: true
+ register: user
+- name: verify results of create user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is changed
+
+- name: test create user2
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user2"
+ password: "{{ cs_resource_prefix }}_password2"
+ last_name: "{{ cs_resource_prefix }}_last_name2"
+ first_name: "{{ cs_resource_prefix }}_first_name2"
+ email: "{{ cs_resource_prefix }}@example2.com"
+ account: "{{ cs_resource_prefix }}_acc"
+ keys_registered: true
+ register: user
+- name: verify results of create user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user2"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name2"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name2"
+ - user.email == "{{ cs_resource_prefix }}@example2.com"
+ - user.account_type == "user"
+ - user.account == "{{ cs_resource_prefix }}_acc"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+ - user.user_api_key is defined
+
+- name: test create user2 idempotence
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user2"
+ password: "{{ cs_resource_prefix }}_password2"
+ last_name: "{{ cs_resource_prefix }}_last_name2"
+ first_name: "{{ cs_resource_prefix }}_first_name2"
+ email: "{{ cs_resource_prefix }}@example2.com"
+ account: "{{ cs_resource_prefix }}_acc"
+ keys_registered: true
+ register: user
+- name: verify results of create user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is not changed
+ - user.username == "{{ cs_resource_prefix }}_user2"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name2"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name2"
+ - user.email == "{{ cs_resource_prefix }}@example2.com"
+ - user.account_type == "user"
+ - user.account == "{{ cs_resource_prefix }}_acc"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+ - user.user_api_key is defined
+
+- name: test update user in check mode
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name1"
+ first_name: "{{ cs_resource_prefix }}_first_name1"
+ email: "{{ cs_resource_prefix }}@example.com1"
+ account: "admin"
+ keys_registered: true
+ register: user
+ check_mode: true
+- name: verify results of update user in check mode
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name"
+ - user.email == "{{ cs_resource_prefix }}@example.com"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+ - user.user_api_key is not defined
+
+- name: test update user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name1"
+ first_name: "{{ cs_resource_prefix }}_first_name1"
+ email: "{{ cs_resource_prefix }}@example.com1"
+ account: "admin"
+ keys_registered: true
+ register: user
+- name: verify results of update user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name1"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name1"
+ - user.email == "{{ cs_resource_prefix }}@example.com1"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+ - user.user_api_key is defined
+
+- name: test update user idempotence
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name1"
+ first_name: "{{ cs_resource_prefix }}_first_name1"
+ email: "{{ cs_resource_prefix }}@example.com1"
+ account: "admin"
+ keys_registered: true
+ register: user
+- name: verify results of update user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is not changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name1"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name1"
+ - user.email == "{{ cs_resource_prefix }}@example.com1"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+ - user.user_api_key is defined
+
+- name: test lock user in check mode
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: user
+ check_mode: true
+- name: verify results of lock user in check mode
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state != "locked"
+ - user.domain == "ROOT"
+
+- name: test lock user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: user
+- name: verify results of lock user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "locked"
+ - user.domain == "ROOT"
+
+- name: test lock user idempotence
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: user
+- name: verify results of lock user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is not changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "locked"
+ - user.domain == "ROOT"
+
+- name: test disable user in check mode
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: disabled
+ register: user
+ check_mode: true
+- name: verify results of disable user in check mode
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state != "disabled"
+ - user.domain == "ROOT"
+
+- name: test disable user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: disabled
+ register: user
+- name: verify results of disable user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "disabled"
+ - user.domain == "ROOT"
+
+- name: test disable user idempotence
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: disabled
+ register: user
+- name: verify results of disable user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is not changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "disabled"
+ - user.domain == "ROOT"
+
+- name: test lock disabled user in check mode
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: user
+ check_mode: true
+- name: verify results of lock disabled user in check mode
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "disabled"
+ - user.domain == "ROOT"
+
+- name: test lock disabled user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: user
+- name: verify results of lock disabled user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "locked"
+ - user.domain == "ROOT"
+
+- name: test lock disabled user idempotence
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: locked
+ register: user
+- name: verify results of lock disabled user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is not changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "locked"
+ - user.domain == "ROOT"
+
+- name: test enable user in check mode
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: enabled
+ register: user
+ check_mode: true
+- name: verify results of enable user in check mode
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state != "enabled"
+ - user.domain == "ROOT"
+
+- name: test enable user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: enabled
+ register: user
+- name: verify results of enable user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+
+- name: test enable user idempotence using unlocked
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: unlocked
+ register: user
+- name: verify results of enable user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is not changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+
+- name: test remove user in check mode
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: user
+ check_mode: true
+- name: verify results of remove user in check mode
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+
+- name: test remove user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: user
+- name: verify results of remove user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+
+- name: test remove user idempotence
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: user
+- name: verify results of remove user idempotence
+ assert:
+ that:
+ - user is successful
+ - user is not changed
+
+- name: test create locked user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ account: "admin"
+ state: locked
+ register: user
+- name: verify results of create locked user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name"
+ - user.email == "{{ cs_resource_prefix }}@example.com"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "locked"
+ - user.domain == "ROOT"
+
+- name: test remove locked user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: user
+- name: verify results of remove locked user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "locked"
+ - user.domain == "ROOT"
+
+- name: test create disabled user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ account: "admin"
+ state: disabled
+ register: user
+- name: verify results of create disabled user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name"
+ - user.email == "{{ cs_resource_prefix }}@example.com"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "disabled"
+ - user.domain == "ROOT"
+
+- name: test remove disabled user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: user
+- name: verify results of remove disabled user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "disabled"
+ - user.domain == "ROOT"
+
+- name: test create enabled user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ password: "{{ cs_resource_prefix }}_password"
+ last_name: "{{ cs_resource_prefix }}_last_name"
+ first_name: "{{ cs_resource_prefix }}_first_name"
+ email: "{{ cs_resource_prefix }}@example.com"
+ account: "admin"
+ state: enabled
+ register: user
+- name: verify results of create enabled user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.first_name == "{{ cs_resource_prefix }}_first_name"
+ - user.last_name == "{{ cs_resource_prefix }}_last_name"
+ - user.email == "{{ cs_resource_prefix }}@example.com"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
+
+- name: test remove enabled user
+ cs_user:
+ username: "{{ cs_resource_prefix }}_user"
+ state: absent
+ register: user
+- name: verify results of remove enabled user
+ assert:
+ that:
+ - user is successful
+ - user is changed
+ - user.username == "{{ cs_resource_prefix }}_user"
+ - user.account_type == "root_admin"
+ - user.account == "admin"
+ - user.state == "enabled"
+ - user.domain == "ROOT"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/tasks/main.yml
new file mode 100644
index 00000000..fdfc2515
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/tasks/main.yml
@@ -0,0 +1,461 @@
+---
+- name: setup cleanup test network
+ cs_network:
+ name: ipr_test_network
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+
+- name: setup create test network
+ cs_network:
+ name: ipr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ vlan: 98
+ start_ip: 10.2.4.2
+ end_ip: 10.2.4.9
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ network_offering: DefaultSharedNetworkOffering
+ register: ipr_net
+- name: verify setup create test network
+ assert:
+ that:
+ - ipr_net is successful
+ - ipr_net is changed
+
+- name: test create a VLAN IP RANGE with missing required param
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ vlan: 98
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ gateway: 10.2.4.1
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: yes
+ register: ipr
+- name: verify test create VLAN IP RANGE with missing required param
+ assert:
+ that:
+ - ipr is not successful
+ - ipr is not changed
+ - 'ipr.msg == "state is present but all of the following are missing: netmask"'
+
+- name: test create a VLAN IP RANGE with conflicting params
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ vlan: 98
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ project: fakeproject
+ account: fakeaccount
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: yes
+ register: ipr
+- name: verify test create VLAN IP RANGE with missing conflicting params
+ assert:
+ that:
+ - ipr is not successful
+ - ipr is not changed
+ - 'ipr.msg == "parameters are mutually exclusive: account|project"'
+
+- name: test create a VLAN IP RANGE in check mode
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ vlan: 98
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ zone: "{{ cs_common_zone_adv }}"
+ register: ipr
+ check_mode: true
+- name: verify test create VLAN IP RANGE in check mode
+ assert:
+ that:
+ - ipr is successful
+ - ipr is changed
+
+- name: test create a VLAN IP RANGE
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ vlan: 98
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ zone: "{{ cs_common_zone_adv }}"
+ register: ipr
+- name: verify test create VLAN IP RANGE
+ assert:
+ that:
+ - ipr is successful
+ - ipr is changed
+ - ipr.vlan == "vlan://98"
+ - ipr.start_ip == "10.2.4.10"
+ - ipr.end_ip == "10.2.4.100"
+ - ipr.gateway == "10.2.4.1"
+ - ipr.netmask == "255.255.255.0"
+ - ipr.network == "ipr_test_network"
+ - ipr.for_virtual_network == false
+
+- name: test create a VLAN IP RANGE idempotence
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ vlan: 98
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ zone: "{{ cs_common_zone_adv }}"
+ register: ipr
+- name: verify test create VLAN IP RANGE idempotence
+ assert:
+ that:
+ - ipr is successful
+ - ipr is not changed
+ - ipr.vlan == "vlan://98"
+ - ipr.start_ip == "10.2.4.10"
+ - ipr.end_ip == "10.2.4.100"
+ - ipr.gateway == "10.2.4.1"
+ - ipr.netmask == "255.255.255.0"
+ - ipr.network == "ipr_test_network"
+ - ipr.for_virtual_network == false
+
+- name: test create a second VLAN IP RANGE in check mode
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.101
+ end_ip: 10.2.4.150
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ zone: "{{ cs_common_zone_adv }}"
+ register: ipr2
+ check_mode: true
+- name: verify test create a second VLAN IP RANGE in check mode
+ assert:
+ that:
+ - ipr2 is successful
+ - ipr2 is changed
+
+- name: test create a second VLAN IP RANGE
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.101
+ end_ip: 10.2.4.150
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ zone: "{{ cs_common_zone_adv }}"
+ register: ipr2
+- name: verify test create a second VLAN IP RANGE
+ assert:
+ that:
+ - ipr2 is successful
+ - ipr2 is changed
+ - ipr2.vlan == "vlan://98"
+ - ipr2.start_ip == "10.2.4.101"
+ - ipr2.end_ip == "10.2.4.150"
+ - ipr2.gateway == "10.2.4.1"
+ - ipr2.netmask == "255.255.255.0"
+ - ipr2.network == "ipr_test_network"
+ - ipr2.for_virtual_network == false
+ - ipr2.id != ipr.id
+
+- name: test create a second VLAN IP RANGE idempotence
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.101
+ end_ip: 10.2.4.150
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ zone: "{{ cs_common_zone_adv }}"
+ register: ipr2
+- name: verify test create a second VLAN IP RANGE idempotence
+ assert:
+ that:
+ - ipr2 is successful
+ - ipr2 is not changed
+ - ipr2.vlan == "vlan://98"
+ - ipr2.start_ip == "10.2.4.101"
+ - ipr2.end_ip == "10.2.4.150"
+ - ipr2.gateway == "10.2.4.1"
+ - ipr2.netmask == "255.255.255.0"
+ - ipr2.network == "ipr_test_network"
+ - ipr2.for_virtual_network == false
+
+- name: test create a single IP VLAN IP RANGE
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.200
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ zone: "{{ cs_common_zone_adv }}"
+ register: ipr3
+- name: verify test create single IP VLAN IP RANGE
+ assert:
+ that:
+ - ipr3 is successful
+ - ipr3 is changed
+ - ipr3.vlan == "vlan://98"
+ - ipr3.start_ip == "10.2.4.200"
+ - ipr3.end_ip == "10.2.4.200"
+ - ipr3.gateway == "10.2.4.1"
+ - ipr3.netmask == "255.255.255.0"
+ - ipr3.network == "ipr_test_network"
+ - ipr3.for_virtual_network == false
+
+- name: test create an IPv4 + IPv6 VLAN IP RANGE
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ vlan: 98
+ start_ip: 10.2.4.151
+ end_ip: 10.2.4.199
+ gateway: 10.2.4.1
+ netmask: 255.255.255.0
+ start_ipv6: 2001:db8::10
+ end_ipv6: 2001:db8::50
+ gateway_ipv6: 2001:db8::1
+ cidr_ipv6: 2001:db8::/64
+ zone: "{{ cs_common_zone_adv }}"
+ register: iprv6
+- name: verify test create an IPv4 + IPv6 VLAN IP RANGE
+ assert:
+ that:
+ - iprv6 is successful
+ - iprv6 is changed
+ - iprv6.vlan == "vlan://98"
+ - iprv6.start_ip == "10.2.4.151"
+ - iprv6.end_ip == "10.2.4.199"
+ - iprv6.gateway == "10.2.4.1"
+ - iprv6.netmask == "255.255.255.0"
+ - iprv6.start_ipv6 == "2001:db8::10"
+ - iprv6.end_ipv6 == "2001:db8::50"
+ - iprv6.gateway_ipv6 == "2001:db8::1"
+ - iprv6.cidr_ipv6 == "2001:db8::/64"
+ - iprv6.network == "ipr_test_network"
+ - iprv6.for_virtual_network == false
+
+- name: test cleanup VLAN IP RANGE in check mode
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ check_mode: true
+ register: ipr
+- name: verify test cleanup VLAN IP RANGE in check mode
+ assert:
+ that:
+ - ipr is successful
+ - ipr is changed
+ - ipr.vlan == "vlan://98"
+ - ipr.start_ip == "10.2.4.10"
+ - ipr.end_ip == "10.2.4.100"
+ - ipr.gateway == "10.2.4.1"
+ - ipr.netmask == "255.255.255.0"
+ - ipr.network == "ipr_test_network"
+ - ipr.for_virtual_network == false
+
+- name: test cleanup VLAN IP RANGE
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: ipr
+- name: verify test cleanup VLAN IP RANGE
+ assert:
+ that:
+ - ipr is successful
+ - ipr is changed
+ - ipr.vlan == "vlan://98"
+ - ipr.start_ip == "10.2.4.10"
+ - ipr.end_ip == "10.2.4.100"
+ - ipr.gateway == "10.2.4.1"
+ - ipr.netmask == "255.255.255.0"
+ - ipr.network == "ipr_test_network"
+ - ipr.for_virtual_network == false
+
+- name: test cleanup VLAN IP RANGE idempotence
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.10
+ end_ip: 10.2.4.100
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: ipr
+- name: verify test cleanup VLAN IP RANGE idempotence
+ assert:
+ that:
+ - ipr is successful
+ - ipr is not changed
+
+- name: test cleanup single IP VLAN IP RANGE
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.200
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: ipr
+- name: verify test cleanup single IP VLAN IP RANGE
+ assert:
+ that:
+ - ipr is successful
+ - ipr is changed
+ - ipr.vlan == "vlan://98"
+ - ipr.start_ip == "10.2.4.200"
+ - ipr.end_ip == "10.2.4.200"
+ - ipr.gateway == "10.2.4.1"
+ - ipr.netmask == "255.255.255.0"
+ - ipr.network == "ipr_test_network"
+ - ipr.for_virtual_network == false
+
+- name: cleanup second VLAN IP RANGE
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.101
+ end_ip: 10.2.4.150
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: ipr2
+- name: verify cleanup second VLAN IP RANGE
+ assert:
+ that:
+ - ipr2 is successful
+ - ipr2 is changed
+ - ipr2.vlan == "vlan://98"
+ - ipr2.start_ip == "10.2.4.101"
+ - ipr2.end_ip == "10.2.4.150"
+ - ipr2.gateway == "10.2.4.1"
+ - ipr2.netmask == "255.255.255.0"
+ - ipr2.network == "ipr_test_network"
+ - ipr2.for_virtual_network == false
+
+- name: test cleanup IPv4 + IPv6 VLAN IP RANGE
+ cs_vlan_ip_range:
+ network: ipr_test_network
+ start_ip: 10.2.4.151
+ end_ip: 10.2.4.199
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: iprv6
+- name: verify test cleanup IPv4 + IPv6 VLAN IP RANGE
+ assert:
+ that:
+ - iprv6 is successful
+ - iprv6 is changed
+ - iprv6.vlan == "vlan://98"
+ - iprv6.start_ip == "10.2.4.151"
+ - iprv6.end_ip == "10.2.4.199"
+ - iprv6.gateway == "10.2.4.1"
+ - iprv6.netmask == "255.255.255.0"
+ - iprv6.start_ipv6 == "2001:db8::10"
+ - iprv6.end_ipv6 == "2001:db8::50"
+ - iprv6.gateway_ipv6 == "2001:db8::1"
+ - iprv6.cidr_ipv6 == "2001:db8::/64"
+ - iprv6.network == "ipr_test_network"
+ - iprv6.for_virtual_network == false
+
+- name: cleanup test network
+ cs_network:
+ name: ipr_test_network
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: ipr_net
+- name: verify cleanup test network
+ assert:
+ that:
+ - ipr_net is successful
+ - ipr_net is changed
+
+# Create a new zone - the default one is enabled
+- name: assure zone for tests
+ cs_zone:
+ name: cs-test-zone
+ state: present
+ dns1: 8.8.8.8
+ network_type: Advanced
+ register: cszone
+
+- name: ensure the zone is disabled
+ cs_zone:
+ name: "{{ cszone.name }}"
+ state: disabled
+
+- name: setup a network for tests
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ isolation_method: VLAN
+ broadcast_domain_range: ZONE
+ state: present
+ register: public_network
+
+- name: setup public network traffic
+ cs_traffic_type:
+ physical_network: "{{ public_network.name }}"
+ traffic_type: Public
+ kvm_networklabel: cloudbr1
+ zone: "{{ public_network.zone }}"
+
+- name: test adding a public IP range
+ cs_vlan_ip_range:
+ end_ip: 10.0.3.250
+ start_ip: 10.0.3.10
+ zone: "{{ cszone.name }}"
+ netmask: 255.255.255.0
+ for_virtual_network: 'yes'
+ gateway: 10.0.3.2
+ vlan: untagged
+ register: public_range
+- name: verify test adding a public IP range
+ assert:
+ that:
+ - public_range is successful
+ - public_range is changed
+ - public_range.physical_network == public_network.id
+ - public_range.vlan == 'vlan://untagged'
+ - public_range.gateway == '10.0.3.2'
+ - public_range.netmask == '255.255.255.0'
+ - public_range.zone == cszone.name
+ - public_range.start_ip == '10.0.3.10'
+ - public_range.end_ip == '10.0.3.250'
+ - public_range.for_systemvms == false
+
+- name: test adding a public IP range for System VMs
+ cs_vlan_ip_range:
+ end_ip: 10.0.4.250
+ start_ip: 10.0.4.10
+ zone: "{{ cszone.name }}"
+ netmask: 255.255.255.0
+ for_virtual_network: 'yes'
+ for_system_vms: 'yes'
+ gateway: 10.0.4.2
+ vlan: untagged
+ register: public_range
+- name: verify test adding a public IP range for System VMs
+ assert:
+ that:
+ - public_range is successful
+ - public_range is changed
+ - public_range.physical_network == public_network.id
+ - public_range.vlan == 'vlan://untagged'
+ - public_range.gateway == '10.0.4.2'
+ - public_range.netmask == '255.255.255.0'
+ - public_range.zone == cszone.name
+ - public_range.start_ip == '10.0.4.10'
+ - public_range.end_ip == '10.0.4.250'
+ - public_range.for_systemvms == true
+
+- name: cleanup the network
+ cs_physical_network:
+ name: net01
+ zone: "{{ cszone.name }}"
+ state: absent
+
+- name: cleanup the zone
+ cs_zone:
+ name: "{{ cszone.name }}"
+ state: absent \ No newline at end of file
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/defaults/main.yml
new file mode 100644
index 00000000..490c6c14
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+test_cs_instance_template: "{{ cs_common_template }}"
+test_cs_instance_offering_1: Small Instance
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/tasks/main.yml
new file mode 100644
index 00000000..51ce5767
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/tasks/main.yml
@@ -0,0 +1,165 @@
+---
+- name: setup instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-snapshot"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ zone: "{{ cs_common_zone_basic }}"
+ register: instance
+- name: verify create instance
+ assert:
+ that:
+ - instance is successful
+
+- name: ensure no snapshot exists
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: snap
+- name: verify setup
+ assert:
+ that:
+ - snap is successful
+
+- name: test fail if missing name
+ cs_vmsnapshot:
+ zone: "{{ cs_common_zone_basic }}"
+ register: snap
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - snap is failed
+ - 'snap.msg.startswith("missing required arguments: ")'
+
+- name: test create snapshot in check mode
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ snapshot_memory: yes
+ register: snap
+ check_mode: true
+- name: verify test create snapshot in check mode
+ assert:
+ that:
+ - snap is changed
+
+- name: test create snapshot
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ snapshot_memory: yes
+ register: snap
+- name: verify test create snapshot
+ assert:
+ that:
+ - snap is changed
+ - snap.display_name == "{{ cs_resource_prefix }}_snapshot"
+
+- name: test create snapshot idempotence
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ snapshot_memory: yes
+ register: snap
+- name: verify test create snapshot idempotence
+ assert:
+ that:
+ - snap is not changed
+ - snap.display_name == "{{ cs_resource_prefix }}_snapshot"
+
+- name: test revert snapshot in check mode
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ state: revert
+ register: snap
+ check_mode: true
+- name: verify test revert snapshot in check mode
+ assert:
+ that:
+ - snap is changed
+ - snap.display_name == "{{ cs_resource_prefix }}_snapshot"
+
+- name: test fail revert unknown snapshot
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot_unknown"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ state: revert
+ register: snap
+ ignore_errors: true
+- name: verify test fail revert unknown snapshot
+ assert:
+ that:
+ - snap is failed
+ - snap.msg == "snapshot not found, could not revert VM"
+
+- name: test revert snapshot
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ state: revert
+ register: snap
+- name: verify test revert snapshot
+ assert:
+ that:
+ - snap is changed
+ - snap.display_name == "{{ cs_resource_prefix }}_snapshot"
+
+- name: test remove snapshot in check mode
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: snap
+ check_mode: true
+- name: verify test remove snapshot in check mode
+ assert:
+ that:
+ - snap is changed
+ - snap.display_name == "{{ cs_resource_prefix }}_snapshot"
+
+- name: test remove snapshot
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: snap
+- name: verify test remove snapshot
+ assert:
+ that:
+ - snap is changed
+ - snap.display_name == "{{ cs_resource_prefix }}_snapshot"
+
+- name: test remove snapshot idempotence
+ cs_vmsnapshot:
+ name: "{{ cs_resource_prefix }}_snapshot"
+ vm: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: snap
+- name: verify test remove snapshot idempotence
+ assert:
+ that:
+ - snap is not changed
+
+- name: cleanup instance
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-snapshot"
+ zone: "{{ cs_common_zone_basic }}"
+ state: expunged
+ register: instance
+- name: verify destroy instance
+ assert:
+ that:
+ - instance is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/defaults/main.yml
new file mode 100644
index 00000000..f1074cf1
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/defaults/main.yml
@@ -0,0 +1,8 @@
+---
+test_cs_instance_1: "{{ cs_resource_prefix }}-vm1"
+test_cs_instance_2: "{{ cs_resource_prefix }}-vm2"
+test_cs_instance_3: "{{ cs_resource_prefix }}-vm3"
+test_cs_instance_template: "{{ cs_common_template }}"
+test_cs_instance_offering_1: Small Instance
+test_cs_disk_offering_1: Custom
+test_cs_volume_to_upload: http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-xen.vhd.bz2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/common.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/common.yml
new file mode 100644
index 00000000..f011f858
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/common.yml
@@ -0,0 +1,322 @@
+---
+- name: setup
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: vol
+- name: verify setup
+ assert:
+ that:
+ - vol is successful
+
+- name: setup instance 1
+ cs_instance:
+ name: "{{ test_cs_instance_1 }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ zone: "{{ cs_common_zone_basic }}"
+ register: instance
+- name: verify create instance
+ assert:
+ that:
+ - instance is successful
+
+- name: setup instance 2
+ cs_instance:
+ name: "{{ test_cs_instance_2 }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ zone: "{{ cs_common_zone_basic }}"
+ register: instance
+- name: verify create instance
+ assert:
+ that:
+ - instance is successful
+
+- name: test fail if missing name
+ cs_volume:
+ zone: "{{ cs_common_zone_basic }}"
+ register: vol
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - vol is failed
+ - "vol.msg == 'missing required arguments: name'"
+
+- name: test create volume in check mode
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ disk_offering: "{{ test_cs_disk_offering_1 }}"
+ size: 20
+ register: vol
+ check_mode: true
+- name: verify results test create volume in check mode
+ assert:
+ that:
+ - vol is changed
+
+- name: test create volume
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ disk_offering: "{{ test_cs_disk_offering_1 }}"
+ size: 20
+ register: vol
+- name: verify results test create volume
+ assert:
+ that:
+ - vol is changed
+ - vol.size == 20 * 1024 ** 3
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+
+- name: test create volume idempotence
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ disk_offering: "{{ test_cs_disk_offering_1 }}"
+ size: 20
+ register: vol
+- name: verify results test create volume idempotence
+ assert:
+ that:
+ - vol is not changed
+ - vol.size == 20 * 1024 ** 3
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+
+- name: test shrink volume in check mode
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ disk_offering: "{{ test_cs_disk_offering_1 }}"
+ size: 10
+ shrink_ok: yes
+ register: vol
+ check_mode: true
+- name: verify results test create volume in check mode
+ assert:
+ that:
+ - vol is changed
+ - vol.size == 20 * 1024 ** 3
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+
+- name: test shrink volume
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ disk_offering: "{{ test_cs_disk_offering_1 }}"
+ size: 10
+ shrink_ok: yes
+ register: vol
+- name: verify results test create volume
+ assert:
+ that:
+ - vol is changed
+ - vol.size == 10 * 1024 ** 3
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+
+- name: test shrink volume idempotence
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ disk_offering: "{{ test_cs_disk_offering_1 }}"
+ size: 10
+ shrink_ok: yes
+ register: vol
+- name: verify results test create volume
+ assert:
+ that:
+ - vol is not changed
+ - vol.size == 10 * 1024 ** 3
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+
+- name: test attach volume in check mode
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ vm: "{{ test_cs_instance_1 }}"
+ state: attached
+ register: vol
+ check_mode: true
+- name: verify results test attach volume in check mode
+ assert:
+ that:
+ - vol is changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+ - vol.attached is not defined
+
+- name: test attach volume
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ vm: "{{ test_cs_instance_1 }}"
+ state: attached
+ register: vol
+- name: verify results test attach volume
+ assert:
+ that:
+ - vol is changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+ - vol.vm == "{{ test_cs_instance_1 }}"
+ - vol.attached is defined
+
+- name: test attach volume idempotence
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ vm: "{{ test_cs_instance_1 }}"
+ state: attached
+ register: vol
+- name: verify results test attach volume idempotence
+ assert:
+ that:
+ - vol is not changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+ - vol.vm == "{{ test_cs_instance_1 }}"
+ - vol.attached is defined
+
+- name: test attach attached volume to another vm in check mdoe
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ vm: "{{ test_cs_instance_2 }}"
+ state: attached
+ register: vol
+ check_mode: true
+- name: verify results test attach attached volume to another vm in check mode
+ assert:
+ that:
+ - vol is changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+ - vol.vm == "{{ test_cs_instance_1 }}"
+ - vol.attached is defined
+
+- name: test attach attached volume to another vm
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ vm: "{{ test_cs_instance_2 }}"
+ state: attached
+ register: vol
+- name: verify results test attach attached volume to another vm
+ assert:
+ that:
+ - vol is changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+ - vol.vm == "{{ test_cs_instance_2 }}"
+ - vol.attached is defined
+
+- name: test attach attached volume to another vm idempotence
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ vm: "{{ test_cs_instance_2 }}"
+ state: attached
+ register: vol
+- name: verify results test attach attached volume to another vm idempotence
+ assert:
+ that:
+ - vol is not changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+ - vol.vm == "{{ test_cs_instance_2 }}"
+ - vol.attached is defined
+
+- name: test detach volume in check mode
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ state: detached
+ register: vol
+ check_mode: true
+- name: verify results test detach volume in check mdoe
+ assert:
+ that:
+ - vol is changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+ - vol.attached is defined
+
+- name: test detach volume
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ state: detached
+ register: vol
+- name: verify results test detach volume
+ assert:
+ that:
+ - vol is changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+ - vol.attached is undefined
+
+- name: test detach volume idempotence
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ state: detached
+ register: vol
+- name: verify results test detach volume idempotence
+ assert:
+ that:
+ - vol is not changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+ - vol.attached is undefined
+
+- name: test delete volume in check mode
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: vol
+ check_mode: true
+- name: verify results test create volume in check mode
+ assert:
+ that:
+ - vol is changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+
+- name: test delete volume
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: vol
+- name: verify results test create volume
+ assert:
+ that:
+ - vol is changed
+ - vol.name == "{{ cs_resource_prefix }}_vol"
+
+- name: test delete volume idempotence
+ cs_volume:
+ name: "{{ cs_resource_prefix }}_vol"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: vol
+- name: verify results test delete volume idempotence
+ assert:
+ that:
+ - vol is not changed
+
+- name: cleanup instance 1
+ cs_instance:
+ name: "{{ test_cs_instance_1 }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: instance
+- name: verify create instance
+ assert:
+ that:
+ - instance is successful
+
+- name: cleanup instance 2
+ cs_instance:
+ name: "{{ test_cs_instance_2 }}"
+ zone: "{{ cs_common_zone_basic }}"
+ state: absent
+ register: instance
+- name: verify create instance
+ assert:
+ that:
+ - instance is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/extract_upload.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/extract_upload.yml
new file mode 100644
index 00000000..5dc70187
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/extract_upload.yml
@@ -0,0 +1,190 @@
+---
+- name: setup
+ cs_volume:
+ zone: "{{ cs_common_zone_adv }}"
+ name: "{{ cs_resource_prefix }}_upload"
+ state: absent
+ register: uploaded_vol
+- name: verify setup
+ assert:
+ that:
+ - uploaded_vol is successful
+
+- name: setup network
+ cs_network:
+ name: "cs_volume_network"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: DefaultSharedNetworkOffering
+ vlan: 2435
+ start_ip: 10.100.129.11
+ end_ip: 10.100.129.250
+ gateway: 10.100.129.1
+ netmask: 255.255.255.0
+ register: net
+- name: verify setup network
+ assert:
+ that:
+ - net is successful
+ - net.name == "cs_volume_network"
+
+- name: setup instance
+ cs_instance:
+ zone: "{{ cs_common_zone_adv }}"
+ name: "{{ test_cs_instance_3 }}"
+ template: "{{ test_cs_instance_template }}"
+ service_offering: "{{ test_cs_instance_offering_1 }}"
+ network: cs_volume_network
+ register: instance
+- name: verify setup instance
+ assert:
+ that:
+ - instance is successful
+
+- name: setup stop instance
+ cs_instance:
+ zone: "{{ cs_common_zone_adv }}"
+ name: "{{ test_cs_instance_3 }}"
+ state: stopped
+ register: instance
+- name: verify stop instance
+ assert:
+ that:
+ - instance is successful
+ - instance.state == 'Stopped'
+
+- name: setup get instance info
+ cs_instance_info:
+ name: "{{ test_cs_instance_3 }}"
+ register: instance
+- name: verify setup get instance info
+ assert:
+ that:
+ - instance is successful
+
+- name: test extract volume in check mode
+ cs_volume:
+ zone: "{{ cs_common_zone_adv }}"
+ state: extracted
+ name: "{{ instance.instances[0].volumes[0].name }}"
+ check_mode: yes
+ register: extracted_vol
+- name: verify test extract volume in check mode
+ assert:
+ that:
+ - extracted_vol is successful
+ - extracted_vol is changed
+ - extracted_vol.state == "Ready"
+ - extracted_vol.name == "{{ instance.instances[0].volumes[0].name }}"
+ - extracted_vol.url is not defined
+
+- name: test extract volume
+ cs_volume:
+ zone: "{{ cs_common_zone_adv }}"
+ state: extracted
+ name: "{{ instance.instances[0].volumes[0].name }}"
+ register: extracted_vol
+- name: verify test extract volume
+ assert:
+ that:
+ - extracted_vol is successful
+ - extracted_vol is changed
+ - extracted_vol.state == "DOWNLOAD_URL_CREATED"
+ - extracted_vol.name == "{{ instance.instances[0].volumes[0].name }}"
+ - extracted_vol.url is defined
+
+- name: test upload volume with missing param
+ cs_volume:
+ zone: "{{ cs_common_zone_adv }}"
+ state: uploaded
+ name: "{{ cs_resource_prefix }}_upload"
+ url: "{{ test_cs_volume_to_upload }}"
+ ignore_errors: yes
+ register: uploaded_vol
+- name: verify upload volume with missing param
+ assert:
+ that:
+ - uploaded_vol is failed
+ - uploaded_vol is not changed
+ - 'uploaded_vol.msg == "state is uploaded but all of the following are missing: format"'
+
+- name: test upload volume in check mode
+ cs_volume:
+ zone: "{{ cs_common_zone_adv }}"
+ state: uploaded
+ name: "{{ cs_resource_prefix }}_upload"
+ format: VHD
+ url: "{{ test_cs_volume_to_upload }}"
+ check_mode: yes
+ register: uploaded_vol
+- name: verify upload volume in check mode
+ assert:
+ that:
+ - uploaded_vol is successful
+ - uploaded_vol is changed
+ - uploaded_vol.name is not defined
+
+- name: test upload volume
+ cs_volume:
+ zone: "{{ cs_common_zone_adv }}"
+ state: uploaded
+ name: "{{ cs_resource_prefix }}_upload"
+ format: VHD
+ url: "{{ test_cs_volume_to_upload }}"
+ register: uploaded_vol
+- name: verify upload volume
+ assert:
+ that:
+ - uploaded_vol is successful
+ - uploaded_vol is changed
+ - uploaded_vol.name == "{{ cs_resource_prefix }}_upload"
+ - uploaded_vol.state == "Uploaded"
+
+- name: test upload volume idempotence
+ cs_volume:
+ zone: "{{ cs_common_zone_adv }}"
+ state: uploaded
+ name: "{{ cs_resource_prefix }}_upload"
+ format: VHD
+ url: "{{ test_cs_volume_to_upload }}"
+ register: uploaded_vol
+- name: verify upload volume idempotence
+ assert:
+ that:
+ - uploaded_vol is successful
+ - uploaded_vol is not changed
+ - uploaded_vol.name == "{{ cs_resource_prefix }}_upload"
+ - uploaded_vol.state == "Uploaded"
+
+- name: delete volume
+ cs_volume:
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ name: "{{ cs_resource_prefix }}_upload"
+ register: uploaded_vol
+- name: verify delete volume
+ assert:
+ that:
+ - uploaded_vol is successful
+ - uploaded_vol is changed
+
+- name: destroy instance
+ cs_instance:
+ zone: "{{ cs_common_zone_adv }}"
+ name: "{{ test_cs_instance_3 }}"
+ state: expunged
+ register: instance
+- name: verify destroy instance
+ assert:
+ that:
+ - instance is successful
+
+- name: delete network
+ cs_network:
+ name: "cs_volume_network"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: net
+- name: verify delete network
+ assert:
+ that:
+ - net is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/main.yml
new file mode 100644
index 00000000..3b863beb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- include_tasks: common.yml
+- include_tasks: extract_upload.yml
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/tasks/main.yml
new file mode 100644
index 00000000..11e310a5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/tasks/main.yml
@@ -0,0 +1,728 @@
+---
+- name: setup
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpc
+- name: verify setup
+ assert:
+ that:
+ - vpc is successful
+
+- name: test fail missing name of vpc
+ cs_vpc:
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: true
+ register: vpc
+- name: verify test fail missing name of vpc
+ assert:
+ that:
+ - vpc is failed
+ - "vpc.msg.startswith('missing required arguments: ')"
+
+- name: test fail missing cidr for vpc
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: true
+ register: vpc
+- name: verify test fail missing cidr for vpc
+ assert:
+ that:
+ - vpc is failed
+ - 'vpc.msg == "state is present but all of the following are missing: cidr"'
+
+- name: test fail missing vpc offering not found
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ vpc_offering: does_not_exist
+ zone: "{{ cs_common_zone_adv }}"
+ cidr: 10.10.1.0/16
+ ignore_errors: true
+ register: vpc
+- name: verify test fail missing cidr for vpc
+ assert:
+ that:
+ - vpc is failed
+ - 'vpc.msg == "VPC offering not found or not enabled: does_not_exist"'
+
+- name: test fail name substring match
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ # Full name is "Redundant VPC offering"
+ vpc_offering: "Redundant"
+ zone: "{{ cs_common_zone_adv }}"
+ cidr: 10.10.1.0/16
+ ignore_errors: true
+ register: vpc
+- name: verify test fail name substring match
+ assert:
+ that:
+ - vpc is failed
+ - 'vpc.msg == "VPC offering not found or not enabled: Redundant"'
+
+- name: test create vpc with custom offering in check mode
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc_custom"
+ display_text: "{{ cs_resource_prefix }}_display_text_custom"
+ cidr: 10.10.1.0/16
+ vpc_offering: Redundant VPC offering
+ network_domain: test.example.com
+ zone: "{{ cs_common_zone_adv }}"
+ state: stopped
+ register: vpc
+ check_mode: true
+- name: verify test create vpc with custom offering in check mode
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+
+- name: test create vpc with custom offering
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc_custom"
+ display_text: "{{ cs_resource_prefix }}_display_text_custom"
+ cidr: 10.10.1.0/16
+ vpc_offering: Redundant VPC offering
+ network_domain: test.example.com
+ zone: "{{ cs_common_zone_adv }}"
+ state: stopped
+ register: vpc
+- name: verify test create vpc with custom offering
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc_custom"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text_custom"
+ - vpc.cidr == "10.10.1.0/16"
+ - vpc.network_domain == "test.example.com"
+
+- name: test create vpc with custom offering idempotence
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc_custom"
+ display_text: "{{ cs_resource_prefix }}_display_text_custom"
+ cidr: 10.10.1.0/16
+ vpc_offering: Redundant VPC offering
+ network_domain: test.example.com
+ zone: "{{ cs_common_zone_adv }}"
+ state: stopped
+ register: vpc
+- name: verify test create vpc with custom offering idempotence
+ assert:
+ that:
+ - vpc is successful
+ - vpc is not changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc_custom"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text_custom"
+ - vpc.cidr == "10.10.1.0/16"
+ - vpc.network_domain == "test.example.com"
+
+- name: test create vpc with default offering in check mode
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+ check_mode: true
+- name: verify test create vpc with default offering in check mode
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+
+- name: test create vpc with default offering
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify test create vpc with default offering
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test create vpc with default offering idempotence
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify test create vpc with default offering idempotence
+ assert:
+ that:
+ - vpc is successful
+ - vpc is not changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test create vpc with default offering idempotence2
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify test create vpc idempotence2
+ assert:
+ that:
+ - vpc is successful
+ - vpc is not changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test update vpc with default offering in check mode
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text2"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+ check_mode: true
+- name: verify test update vpc with default offering in check mode
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test update vpc with default offering
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text2"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify test update vpc with default offering
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text2"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test update vpc with default offering idempotence
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text2"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify test update vpc idempotence
+ assert:
+ that:
+ - vpc is successful
+ - vpc is not changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text2"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test restart vpc with default offering with clean up in check mode
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text2"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ clean_up: true
+ state: restarted
+ register: vpc
+ check_mode: true
+- name: verify test restart vpc with default offering with clean up in check mode
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text2"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test restart vpc with default offering with clean up
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text2"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ clean_up: true
+ state: restarted
+ register: vpc
+- name: verify test restart vpc with default offering with clean up
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text2"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test restart vpc with default offering without clean up
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text2"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ state: restarted
+ register: vpc
+- name: verify test restart vpc with default offering without clean up
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text2"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test create network in vpc in check mode
+ cs_network:
+ name: "{{ cs_resource_prefix }}_net_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: Offering for Isolated Vpc networks with Source Nat service enabled
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ gateway: 10.10.0.1
+ netmask: 255.255.255.0
+ register: vpc_net
+ check_mode: true
+- name: verify test create network in vpc in check mode
+ assert:
+ that:
+ - vpc_net is successful
+ - vpc_net is changed
+
+- name: test create network in vpc
+ cs_network:
+ name: "{{ cs_resource_prefix }}_net_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: Offering for Isolated Vpc networks with Source Nat service enabled
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ gateway: 10.10.0.1
+ netmask: 255.255.255.0
+ register: vpc_net
+- name: verify test create network in vpc
+ assert:
+ that:
+ - vpc_net is successful
+ - vpc_net is changed
+ - vpc_net.name == "{{ cs_resource_prefix }}_net_vpc"
+
+- name: test create network in vpc idempotence
+ cs_network:
+ name: "{{ cs_resource_prefix }}_net_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ network_offering: Offering for Isolated Vpc networks with Source Nat service enabled
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ gateway: 10.10.0.1
+ netmask: 255.255.255.0
+ register: vpc_net
+- name: verify test create network in vpc idempotence
+ assert:
+ that:
+ - vpc_net is successful
+ - vpc_net is not changed
+ - vpc_net.name == "{{ cs_resource_prefix }}_net_vpc"
+
+- name: test create instance in vpc in check mode
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-vpc"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ register: instance
+ check_mode: true
+- name: verify test create instance in vpc in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+
+- name: test create instance in vpc
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-vpc"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ register: instance
+- name: verify test create instance in vpc
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-vpc"
+ - instance.state == "Running"
+
+- name: test create instance in vpc idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-vpc"
+ template: "{{ cs_common_template }}"
+ service_offering: "{{ cs_common_service_offering }}"
+ zone: "{{ cs_common_zone_adv }}"
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ register: instance
+- name: verify test create instance in vpc idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-vpc"
+ - instance.state == "Running"
+
+- name: test get ip address in vpc
+ cs_ip_address:
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: ip_address
+ when: instance.public_ip is undefined
+
+- name: test static nat in vpc in check mode
+ cs_staticnat:
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ ip_address: "{{ ip_address.ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ register: static_nat
+ check_mode: true
+- name: verify test static nat in vpc in check mode
+ assert:
+ that:
+ - static_nat is successful
+ - static_nat is changed
+
+- name: test static nat in vpc
+ cs_staticnat:
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ ip_address: "{{ ip_address.ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ register: static_nat
+- name: verify test static nat in vpc
+ assert:
+ that:
+ - static_nat is successful
+ - static_nat is changed
+
+- name: test static nat in vpc idempotence
+ cs_staticnat:
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ ip_address: "{{ ip_address.ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ register: static_nat
+- name: verify test static nat in vpc idempotence
+ assert:
+ that:
+ - static_nat is successful
+ - static_nat is not changed
+
+- name: test remove static nat in vpc in check mode
+ cs_staticnat:
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ ip_address: "{{ ip_address.ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ state: absent
+ register: static_nat
+ check_mode: true
+- name: verify test remove static nat in vpc in check mode
+ assert:
+ that:
+ - static_nat is successful
+ - static_nat is changed
+
+- name: test remove static nat in vpc
+ cs_staticnat:
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ ip_address: "{{ ip_address.ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ state: absent
+ register: static_nat
+- name: verify test remove static nat in vpc
+ assert:
+ that:
+ - static_nat is successful
+ - static_nat is changed
+
+- name: test remove static nat in vpc idempotence
+ cs_staticnat:
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ ip_address: "{{ ip_address.ip_address }}"
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ state: absent
+ register: static_nat
+- name: verify test remove static nat in vpc idempotence
+ assert:
+ that:
+ - static_nat is successful
+ - static_nat is not changed
+
+- name: test create port forwarding in vpc in check mode
+ cs_portforward:
+ ip_address: "{{ ip_address.ip_address }}"
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ public_port: 80
+ private_port: 8080
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: port_forward
+ check_mode: true
+- name: verify test create port forwarding in vpc in check mode
+ assert:
+ that:
+ - port_forward is successful
+ - port_forward is changed
+
+- name: test create port forwarding in vpc
+ cs_portforward:
+ ip_address: "{{ ip_address.ip_address }}"
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ public_port: 80
+ private_port: 8080
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: port_forward
+- name: verify test create port forwarding in vpc
+ assert:
+ that:
+ - port_forward is successful
+ - port_forward is changed
+
+- name: test create port forwarding in vpc idempotence
+ cs_portforward:
+ ip_address: "{{ ip_address.ip_address }}"
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ public_port: 80
+ private_port: 8080
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: port_forward
+- name: verify test create port forwarding in vpc idempotence
+ assert:
+ that:
+ - port_forward is successful
+ - port_forward is not changed
+
+- name: test remove port forwarding in vpc in check mode
+ cs_portforward:
+ ip_address: "{{ ip_address.ip_address }}"
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ public_port: 80
+ private_port: 8080
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: port_forward
+ check_mode: true
+- name: verify test remove port forwarding in vpc in check mode
+ assert:
+ that:
+ - port_forward is successful
+ - port_forward is changed
+
+- name: test remove port forwarding in vpc
+ cs_portforward:
+ ip_address: "{{ ip_address.ip_address }}"
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ public_port: 80
+ private_port: 8080
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: port_forward
+- name: verify test remove port forwarding in vpc
+ assert:
+ that:
+ - port_forward is successful
+ - port_forward is changed
+
+- name: test remove port forwarding in vpc idempotence
+ cs_portforward:
+ ip_address: "{{ ip_address.ip_address }}"
+ vm: "{{ cs_resource_prefix }}-vm-vpc"
+ public_port: 80
+ private_port: 8080
+ network: "{{ cs_resource_prefix }}_net_vpc"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: port_forward
+- name: verify test remove port forwarding in vpc idempotence
+ assert:
+ that:
+ - port_forward is successful
+ - port_forward is not changed
+
+- name: test remove ip address from vpc
+ cs_ip_address:
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ ip_address: "{{ ip_address.ip_address }}"
+ state: absent
+ register: ip_address_removed
+- name: verify test remove ip address from vpc
+ assert:
+ that:
+ - ip_address_removed is successful
+ - ip_address_removed is changed
+
+- name: test remove instance in vpc in check mdoe
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+ register: instance
+ check_mode: true
+- name: verify test remove instance in vpc in check mode
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-vpc"
+ - instance.state == "Running"
+
+- name: test remove instance in vpc
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+ register: instance
+- name: verify test remove instance in vpc
+ assert:
+ that:
+ - instance is successful
+ - instance is changed
+ - instance.name == "{{ cs_resource_prefix }}-vm-vpc"
+ - instance.state == "Running"
+
+- name: test remove instance in vpc idempotence
+ cs_instance:
+ name: "{{ cs_resource_prefix }}-vm-vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: expunged
+ register: instance
+- name: verify test remove instance in vpc idempotence
+ assert:
+ that:
+ - instance is successful
+ - instance is not changed
+
+- name: test remove network in vpc in check mode
+ cs_network:
+ name: "{{ cs_resource_prefix }}_net_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ register: vpc_net
+ check_mode: true
+- name: verify test remove network in vpc in check mode
+ assert:
+ that:
+ - vpc_net is successful
+ - vpc_net is changed
+ - vpc_net.name == "{{ cs_resource_prefix }}_net_vpc"
+
+- name: test remove network in vpc
+ cs_network:
+ name: "{{ cs_resource_prefix }}_net_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ register: vpc_net
+- name: verify test remove network in vpc
+ assert:
+ that:
+ - vpc_net is successful
+ - vpc_net is changed
+ - vpc_net.name == "{{ cs_resource_prefix }}_net_vpc"
+
+- name: test remove network in vpc idempotence
+ cs_network:
+ name: "{{ cs_resource_prefix }}_net_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ register: vpc_net
+- name: verify test remove network in vpc idempotence
+ assert:
+ that:
+ - vpc_net is successful
+ - vpc_net is not changed
+
+- name: test remove vpc with default offering in check mode
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+ check_mode: true
+- name: verify test remove vpc with default offering in check mode
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text2"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test remove vpc with default offering
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify test remove vpc with default offering
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc"
+ - vpc.display_text == "{{ cs_resource_prefix }}_display_text2"
+ - vpc.cidr == "10.10.0.0/16"
+
+- name: test remove vpc with default offering idempotence
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ register: vpc
+- name: verify test remove vpc idempotence
+ assert:
+ that:
+ - vpc is successful
+ - vpc is not changed
+
+- name: test remove vpc with custom offering
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc_custom"
+ state: absent
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify test remove vpc with custom offering
+ assert:
+ that:
+ - vpc is successful
+ - vpc is changed
+ - vpc.name == "{{ cs_resource_prefix }}_vpc_custom"
+ - vpc.cidr == "10.10.1.0/16"
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/tasks/main.yml
new file mode 100644
index 00000000..ebbeaf91
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/tasks/main.yml
@@ -0,0 +1,427 @@
+---
+- name: setup
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ register: vpcoffer
+- name: verify setup
+ assert:
+ that:
+ - vpcoffer is successful
+
+- name: test fail if missing name
+ cs_vpc_offering:
+ register: vpcoffer
+ ignore_errors: true
+- name: verify results of fail if missing name
+ assert:
+ that:
+ - vpcoffer is failed
+ - 'vpcoffer.msg == "missing required arguments: name"'
+
+- name: test fail if missing params
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ register: vpcoffer
+ ignore_errors: true
+- name: verify results of fail if missing params
+ assert:
+ that:
+ - vpcoffer is failed
+ - 'vpcoffer.msg == "missing required arguments: display_text, supported_services"'
+
+- name: test create vpc offer in check mode
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ register: vpcoffer
+ check_mode: yes
+- name: verify results of vpc offer in check mode
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+
+- name: test create vpc offer
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ register: vpcoffer
+- name: verify results of vpc offer
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description"
+ - vpcoffer.distributed == false
+ - vpcoffer.region_level == false
+
+- name: test create vpc offer idempotence
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ register: vpcoffer
+- name: verify results of create vpc offer idempotence
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is not changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description"
+ - vpcoffer.distributed == false
+ - vpcoffer.region_level == false
+
+- name: test enabling existing vpc offer in check_mode
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: enabled
+ register: vpcoffer
+ check_mode: yes
+- name: verify results of enabling existing vpc offer in check_mode
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description"
+
+- name: test enabling existing vpc offer
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: enabled
+ register: vpcoffer
+- name: verify results of enabling existing vpc offer
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Enabled"
+ - vpcoffer.display_text == "vpc offering description"
+
+- name: test enabling existing vpc offer idempotence
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: enabled
+ register: vpcoffer
+- name: verify results of enabling existing vpc idempotence
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is not changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Enabled"
+ - vpcoffer.display_text == "vpc offering description"
+
+- name: test disabling vpc offer in check_mode
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: vpcoffer
+ check_mode: yes
+- name: verify results of disabling vpc offer in check_mode
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Enabled"
+ - vpcoffer.display_text == "vpc offering description"
+
+- name: test disabling vpc offer
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: vpcoffer
+- name: verify results of disabling vpc offer
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description"
+
+- name: test disabling vpc offer idempotence
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: vpcoffer
+- name: verify results of disabling vpc idempotence
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is not changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description"
+
+- name: test rename vpc offer in check_mode
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description renamed"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: vpcoffer
+ check_mode: yes
+- name: verify results of rename vpc offer in check_mode
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description"
+
+- name: test rename vpc offer
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description renamed"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: vpcoffer
+- name: verify results of rename vpc offer
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description renamed"
+
+- name: test rename vpc offer idempotence
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description renamed"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: disabled
+ register: vpcoffer
+- name: verify results of rename vpc offer idempotence
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is not changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description renamed"
+
+- name: test update offer with minimal params in check_mode
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description update"
+ register: vpcoffer
+ check_mode: yes
+- name: verify results of update offer with minimal params in check_mode
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description renamed"
+
+- name: test update offer with minimal params
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description update"
+ register: vpcoffer
+- name: verify results of update offer with minimal params
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description update"
+
+- name: test update offer with minimal params idempotency
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description update"
+ register: vpcoffer
+- name: verify results of update offer with minimal params idempotency
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is not changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description update"
+
+- name: test remove vpc offer in check_mode
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ register: vpcoffer
+ check_mode: yes
+- name: verify results of rename vpc offer in check_mode
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Disabled"
+ - vpcoffer.display_text == "vpc offering description update"
+
+- name: test remove vpc offer
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ register: vpcoffer
+- name: verify results of rename vpc offer
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+
+- name: test remove vpc offer idempotence
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ register: vpcoffer
+- name: verify results of rename vpc offer idempotence
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is not changed
+
+- name: test create enabled vpc offer in check mode
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: enabled
+ register: vpcoffer
+ check_mode: yes
+- name: verify results of create enabled vpc offer in check mode
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+
+- name: test create enabled vpc offer
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: enabled
+ register: vpcoffer
+- name: verify results of create enabled vpc offer
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Enabled"
+ - vpcoffer.display_text == "vpc offering description"
+
+- name: test create enabled vpc offer idempotence
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: enabled
+ register: vpcoffer
+- name: verify results of create enabled vpc offer idempotence
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is not changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc"
+ - vpcoffer.state == "Enabled"
+ - vpcoffer.display_text == "vpc offering description"
+
+- name: test create enabled region level vpc offer with distrubuted router
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc_drl"
+ display_text: "vpc offering description"
+ supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ]
+ service_providers:
+ - { service: 'dns', provider: 'virtualrouter' }
+ - { service: 'dhcp', provider: 'virtualrouter' }
+ state: enabled
+ service_capabilities:
+ - {service: 'Connectivity', capabilitytype: 'DistributedRouter', capabilityvalue: true}
+ - {service: 'Connectivity', capabilitytype: 'RegionLevelVPC', capabilityvalue: true}
+ register: vpcoffer
+- name: verify results of create enabled region level vpc offer with distrubuted router
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+ - vpcoffer.name == "{{ cs_resource_prefix }}_vpc_drl"
+ - vpcoffer.state == "Enabled"
+ - vpcoffer.display_text == "vpc offering description"
+ - vpcoffer.distributed == true
+ - vpcoffer.region_level == true
+
+- name: remove vpc offer
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc"
+ state: absent
+ register: vpcoffer
+- name: verify results of remove vpc offer
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
+
+- name: remove region level vpc offer with distrubuted router
+ cs_vpc_offering:
+ name: "{{ cs_resource_prefix }}_vpc_drl"
+ state: absent
+ register: vpcoffer
+- name: verify results of remove region level vpc offer with distrubuted router
+ assert:
+ that:
+ - vpcoffer is successful
+ - vpcoffer is changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/tasks/main.yml
new file mode 100644
index 00000000..97e1d941
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/tasks/main.yml
@@ -0,0 +1,205 @@
+---
+- name: setup vpc
+ cs_vpc:
+ name: my_vpc
+ display_text: my_vpc
+ cidr: 10.10.1.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify setup vpc
+ assert:
+ that:
+ - vpc is successful
+
+- name: setup customer gateway
+ cs_vpn_customer_gateway:
+ name: my_vpn_customer_gateway
+ cidr: 192.168.123.0/24
+ esp_policy: aes256-sha1;modp1536
+ gateway: 10.11.1.1
+ ike_policy: aes256-sha1;modp1536
+ ipsec_psk: ~S3¢r3Tk3Y¼
+ esp_lifetime: 3600
+ register: vcg
+- name: setup customer gateway
+ assert:
+ that:
+ - vcg is successful
+
+- name: setup remove vpn connection
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpn_conn
+- name: verify setup remove vpn connection
+ assert:
+ that:
+ - vpn_conn is successful
+
+- name: setup vpn gateway absent
+ cs_vpn_gateway:
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpn_gateway
+- name: verify setup vpn gateway absent
+ assert:
+ that:
+ - vpn_gateway is successful
+
+- name: test fail create vpn connection without gateway and force
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ ignore_errors: yes
+ register: vpn_conn
+- name: verify test fail create vpn connection without gateway and force
+ assert:
+ that:
+ - vpn_conn is failed
+ - vpn_conn.msg == "VPN gateway not found and not forced to create one"
+
+- name: test create vpn connection with force in check mode
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ force: yes
+ zone: "{{ cs_common_zone_adv }}"
+ check_mode: yes
+ register: vpn_conn
+- name: verify test create vpn connection with force in check mode
+ assert:
+ that:
+ - vpn_conn is changed
+
+- name: test create vpn connection with force
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ force: yes
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpn_conn
+- name: verify test create vpn connection with force
+ assert:
+ that:
+ - vpn_conn is changed
+ - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway"
+ - vpn_conn.vpc == "my_vpc"
+
+- name: test create vpn connection with force idempotence
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ force: yes
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpn_conn
+- name: verify test create vpn connection with force idempotence
+ assert:
+ that:
+ - vpn_conn is not changed
+ - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway"
+ - vpn_conn.vpc == "my_vpc"
+
+- name: test remove vpn connection in check mode
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ check_mode: yes
+ register: vpn_conn
+- name: verify test remove vpn connection in check mode
+ assert:
+ that:
+ - vpn_conn is changed
+ - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway"
+ - vpn_conn.vpc == "my_vpc"
+
+- name: test remove vpn connection
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpn_conn
+- name: verify test remove vpn connection
+ assert:
+ that:
+ - vpn_conn is changed
+ - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway"
+ - vpn_conn.vpc == "my_vpc"
+
+- name: test remove vpn connection idempotence
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpn_conn
+- name: verify test remove vpn connection idempotence
+ assert:
+ that:
+ - vpn_conn is not changed
+
+- name: setup create vpn gateway
+ cs_vpn_gateway:
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpn_gateway
+- name: verify setup create vpn gateway
+ assert:
+ that:
+ - vpn_gateway is success
+
+- name: test create vpn connection without force in check mode
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ check_mode: yes
+ register: vpn_conn
+- name: verify test create vpn connection without force in check mode
+ assert:
+ that:
+ - vpn_conn is changed
+
+- name: test create vpn connection without force
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpn_conn
+- name: verify test create vpn connection without force
+ assert:
+ that:
+ - vpn_conn is changed
+ - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway"
+ - vpn_conn.vpc == "my_vpc"
+
+- name: test create vpn connection without force
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpn_conn
+- name: verify test create vpn connection without force
+ assert:
+ that:
+ - vpn_conn is not changed
+ - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway"
+ - vpn_conn.vpc == "my_vpc"
+
+- name: cleanup remove vpn connection
+ cs_vpn_connection:
+ vpn_customer_gateway: my_vpn_customer_gateway
+ vpc: my_vpc
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpn_conn
+- name: verify cleanup remove vpn connection idempotence
+ assert:
+ that:
+ - vpn_conn is successful
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/tasks/main.yml
new file mode 100644
index 00000000..d18d4b6f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/tasks/main.yml
@@ -0,0 +1,208 @@
+---
+- name: setup vpn customer gateway absent
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ state: absent
+ register: vcg
+- name: verify setup vpn customer gateway absent
+ assert:
+ that:
+ - vcg is successful
+
+- name: test create vpn customer gateway in check mode
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ cidr: 192.168.123.0/24
+ esp_policy: aes256-sha1;modp1536
+ gateway: 10.10.0.1
+ ike_policy: aes256-sha1;modp1536
+ ipsec_psk: ~S3¢r3Tk3Y¼
+ esp_lifetime: 3600
+ check_mode: true
+ register: vcg
+- name: verify test create vpn customer gateway in check mode
+ assert:
+ that:
+ - vcg is changed
+
+- name: test create vpn customer gateway
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ cidr: 192.168.123.0/24
+ esp_policy: aes256-sha1;modp1536
+ gateway: 10.10.0.1
+ ike_policy: aes256-sha1;modp1536
+ ipsec_psk: ~S3¢r3Tk3Y¼
+ esp_lifetime: 3600
+ register: vcg
+- name: verify test create vpn customer gateway
+ assert:
+ that:
+ - vcg is changed
+ - "vcg.cidrs == ['192.168.123.0/24']"
+ - vcg.dpd == false
+ - vcg.esp_lifetime == 3600
+ - vcg.esp_policy == 'aes256-sha1;modp1536'
+ - vcg.force_encap == false
+ - vcg.ike_policy == 'aes256-sha1;modp1536'
+ - vcg.gateway == '10.10.0.1'
+ - vcg.name == 'ansible_vpn_customer_gw'
+ - vcg.ike_lifetime == 86400
+
+- name: test create vpn customer gateway idempotency
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ cidr: 192.168.123.0/24
+ esp_policy: aes256-sha1;modp1536
+ gateway: 10.10.0.1
+ ike_policy: aes256-sha1;modp1536
+ ipsec_psk: ~S3¢r3Tk3Y¼
+ esp_lifetime: 3600
+ register: vcg
+- name: verify test create vpn customer gateway idempotency
+ assert:
+ that:
+ - vcg is not changed
+ - "vcg.cidrs == ['192.168.123.0/24']"
+ - vcg.dpd == false
+ - vcg.esp_lifetime == 3600
+ - vcg.esp_policy == 'aes256-sha1;modp1536'
+ - vcg.force_encap == false
+ - vcg.ike_policy == 'aes256-sha1;modp1536'
+ - vcg.gateway == '10.10.0.1'
+ - vcg.name == 'ansible_vpn_customer_gw'
+ - vcg.ike_lifetime == 86400
+
+- name: test update vpn customer gateway in check mode
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ cidrs:
+ - 192.168.123.0/24
+ - 192.168.124.0/24
+ esp_policy: aes256-sha1;modp1536
+ gateway: 10.10.1.1
+ ike_policy: aes256-sha1;modp1536
+ ipsec_psk: ~S3¢r3Tk3Y@
+ esp_lifetime: 1800
+ ike_lifetime: 23200
+ force_encap: true
+ check_mode: true
+ register: vcg
+- name: verify test update vpn customer gateway in check mode
+ assert:
+ that:
+ - vcg is changed
+ - "vcg.cidrs == ['192.168.123.0/24']"
+ - vcg.dpd == false
+ - vcg.esp_lifetime == 3600
+ - vcg.esp_policy == 'aes256-sha1;modp1536'
+ - vcg.force_encap == false
+ - vcg.ike_policy == 'aes256-sha1;modp1536'
+ - vcg.gateway == '10.10.0.1'
+ - vcg.name == 'ansible_vpn_customer_gw'
+ - vcg.ike_lifetime == 86400
+
+- name: test update vpn customer gateway
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ cidrs:
+ - 192.168.123.0/24
+ - 192.168.124.0/24
+ esp_policy: aes256-sha1;modp1536
+ gateway: 10.10.1.1
+ ike_policy: aes256-sha1;modp1536
+ ipsec_psk: ~S3¢r3Tk3Y@
+ esp_lifetime: 1800
+ ike_lifetime: 23200
+ force_encap: true
+ register: vcg
+- name: verify test update vpn customer gateway
+ assert:
+ that:
+ - vcg is changed
+ - "vcg.cidrs == ['192.168.123.0/24', '192.168.124.0/24']"
+ - vcg.dpd == false
+ - vcg.esp_lifetime == 1800
+ - vcg.esp_policy == 'aes256-sha1;modp1536'
+ - vcg.force_encap == true
+ - vcg.ike_policy == 'aes256-sha1;modp1536'
+ - vcg.gateway == '10.10.1.1'
+ - vcg.name == 'ansible_vpn_customer_gw'
+ - vcg.ike_lifetime == 23200
+
+- name: test update vpn customer gateway idempotence
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ cidrs:
+ - 192.168.123.0/24
+ - 192.168.124.0/24
+ esp_policy: aes256-sha1;modp1536
+ gateway: 10.10.1.1
+ ike_policy: aes256-sha1;modp1536
+ ipsec_psk: ~S3¢r3Tk3Y@
+ esp_lifetime: 1800
+ ike_lifetime: 23200
+ force_encap: true
+ register: vcg
+- name: verify test update vpn customer gateway idempotence
+ assert:
+ that:
+ - vcg is not changed
+ - "vcg.cidrs == ['192.168.123.0/24', '192.168.124.0/24']"
+ - vcg.dpd == false
+ - vcg.esp_lifetime == 1800
+ - vcg.esp_policy == 'aes256-sha1;modp1536'
+ - vcg.force_encap == true
+ - vcg.ike_policy == 'aes256-sha1;modp1536'
+ - vcg.gateway == '10.10.1.1'
+ - vcg.name == 'ansible_vpn_customer_gw'
+ - vcg.ike_lifetime == 23200
+
+- name: test remove vpn customer gateway in check mode
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ state: absent
+ check_mode: true
+ register: vcg
+- name: verify test remove vpn customer gateway in check mode
+ assert:
+ that:
+ - vcg is changed
+ - "vcg.cidrs == ['192.168.123.0/24', '192.168.124.0/24']"
+ - vcg.dpd == false
+ - vcg.esp_lifetime == 1800
+ - vcg.esp_policy == 'aes256-sha1;modp1536'
+ - vcg.force_encap == true
+ - vcg.ike_policy == 'aes256-sha1;modp1536'
+ - vcg.gateway == '10.10.1.1'
+ - vcg.name == 'ansible_vpn_customer_gw'
+ - vcg.ike_lifetime == 23200
+
+- name: test remove vpn customer gateway
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ state: absent
+ register: vcg
+- name: verify test remove vpn customer gateway
+ assert:
+ that:
+ - vcg is changed
+ - "vcg.cidrs == ['192.168.123.0/24', '192.168.124.0/24']"
+ - vcg.dpd == false
+ - vcg.esp_lifetime == 1800
+ - vcg.esp_policy == 'aes256-sha1;modp1536'
+ - vcg.force_encap == true
+ - vcg.ike_policy == 'aes256-sha1;modp1536'
+ - vcg.gateway == '10.10.1.1'
+ - vcg.name == 'ansible_vpn_customer_gw'
+ - vcg.ike_lifetime == 23200
+
+- name: test remove vpn customer gateway idempotence
+ cs_vpn_customer_gateway:
+ name: ansible_vpn_customer_gw
+ state: absent
+ register: vcg
+- name: verify test remove vpn customer gateway idempotence
+ assert:
+ that:
+ - vcg is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/tasks/main.yml
new file mode 100644
index 00000000..2dd7a445
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/tasks/main.yml
@@ -0,0 +1,108 @@
+---
+- name: setup vpc
+ cs_vpc:
+ name: "{{ cs_resource_prefix }}_vpc"
+ display_text: "{{ cs_resource_prefix }}_display_text"
+ cidr: 10.10.0.0/16
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpc
+- name: verify setup vpc
+ assert:
+ that:
+ - vpc is successful
+
+- name: setup vpn gateway absent
+ cs_vpn_gateway:
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpn_gateway
+- name: verify setup vpn gateway absent
+ assert:
+ that:
+ - vpn_gateway is successful
+
+- name: test fail missing param vpc for vpn gateway
+ cs_vpn_gateway:
+ ignore_errors: true
+ register: vpn_gateway
+- name: verify test fail missing param vpc for vpn gateway
+ assert:
+ that:
+ - vpn_gateway is failed
+ - "vpn_gateway.msg.startswith('missing required arguments: ')"
+
+- name: test create vpn gateway in check mode
+ cs_vpn_gateway:
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpn_gateway
+ check_mode: true
+- name: verify test create vpn gateway in check mode
+ assert:
+ that:
+ - vpn_gateway is successful
+ - vpn_gateway is changed
+
+- name: test create vpn gateway
+ cs_vpn_gateway:
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpn_gateway
+- name: verify test create vpn gateway
+ assert:
+ that:
+ - vpn_gateway is successful
+ - vpn_gateway is changed
+ - vpn_gateway.vpc == "{{ cs_resource_prefix }}_vpc"
+
+- name: test create vpn gateway idempotence
+ cs_vpn_gateway:
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ register: vpn_gateway
+- name: verify test create vpn gateway idempotence
+ assert:
+ that:
+ - vpn_gateway is successful
+ - vpn_gateway is not changed
+ - vpn_gateway.vpc == "{{ cs_resource_prefix }}_vpc"
+
+- name: test remove vpn gateway in check mode
+ cs_vpn_gateway:
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpn_gateway
+ check_mode: true
+- name: verify test remove vpn gateway in check mode
+ assert:
+ that:
+ - vpn_gateway is successful
+ - vpn_gateway is changed
+ - vpn_gateway.vpc == "{{ cs_resource_prefix }}_vpc"
+
+- name: test remove vpn gateway
+ cs_vpn_gateway:
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpn_gateway
+- name: verify test remove vpn gateway
+ assert:
+ that:
+ - vpn_gateway is successful
+ - vpn_gateway is changed
+ - vpn_gateway.vpc == "{{ cs_resource_prefix }}_vpc"
+
+- name: test remove vpn gateway idempotence
+ cs_vpn_gateway:
+ vpc: "{{ cs_resource_prefix }}_vpc"
+ zone: "{{ cs_common_zone_adv }}"
+ state: absent
+ register: vpn_gateway
+- name: verify test remove vpn gateway idempotence
+ assert:
+ that:
+ - vpn_gateway is successful
+ - vpn_gateway is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/aliases
new file mode 100644
index 00000000..a315c1b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/aliases
@@ -0,0 +1,2 @@
+cloud/cs
+shippable/cs/group2
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/tasks/main.yml
new file mode 100644
index 00000000..9137db44
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/tasks/main.yml
@@ -0,0 +1,205 @@
+---
+- name: setup zone is absent
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: zone
+- name: verify setup zone absent
+ assert:
+ that:
+ - zone is successful
+
+- name: test fail missing param
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ register: zone
+ ignore_errors: true
+- name: verify test fail missing param
+ assert:
+ that:
+ - zone is failed
+ - "zone.msg == 'missing required arguments: dns1'"
+
+- name: test create zone in check mode
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ network_type: Basic
+ register: zone
+ check_mode: true
+- name: verify test create zone in check mode
+ assert:
+ that:
+ - zone is successful
+ - zone is changed
+
+- name: test create zone
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ network_type: Basic
+ register: zone
+- name: verify test create zone
+ assert:
+ that:
+ - zone is successful
+ - zone is changed
+ - zone.dns1 == "8.8.8.8"
+ - zone.dns2 == "8.8.4.4"
+ - zone.internal_dns1 == "8.8.8.8"
+ - zone.internal_dns2 == "8.8.4.4"
+ - zone.local_storage_enabled == false
+ - zone.network_type == "Basic"
+ - zone.zone_token != ""
+ - zone.securitygroups_enabled == true
+ - zone.dhcp_provider == "VirtualRouter"
+
+- name: test create zone idempotency
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ network_type: Basic
+ register: zone
+- name: verify test create zone idempotency
+ assert:
+ that:
+ - zone is successful
+ - zone is not changed
+ - zone.dns1 == "8.8.8.8"
+ - zone.dns2 == "8.8.4.4"
+ - zone.internal_dns1 == "8.8.8.8"
+ - zone.internal_dns2 == "8.8.4.4"
+ - zone.local_storage_enabled == false
+ - zone.network_type == "Basic"
+ - zone.zone_token != ""
+ - zone.securitygroups_enabled == true
+ - zone.dhcp_provider == "VirtualRouter"
+
+- name: test update zone in check mode
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ internal_dns1: 10.10.1.100
+ internal_dns2: 10.10.1.101
+ local_storage_enabled: true
+ network_type: Basic
+ register: zone
+ check_mode: true
+- name: verify test update zone in check mode
+ assert:
+ that:
+ - zone is successful
+ - zone is changed
+ - zone.dns1 == "8.8.8.8"
+ - zone.dns2 == "8.8.4.4"
+ - zone.internal_dns1 == "8.8.8.8"
+ - zone.internal_dns2 == "8.8.4.4"
+ - zone.local_storage_enabled == false
+ - zone.network_type == "Basic"
+ - zone.zone_token != ""
+ - zone.securitygroups_enabled == true
+ - zone.dhcp_provider == "VirtualRouter"
+
+- name: test update zone
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ internal_dns1: 10.10.1.100
+ internal_dns2: 10.10.1.101
+ local_storage_enabled: true
+ network_type: Basic
+ register: zone
+- name: verify test update zone
+ assert:
+ that:
+ - zone is successful
+ - zone is changed
+ - zone.dns1 == "8.8.8.8"
+ - zone.dns2 == "8.8.4.4"
+ - zone.internal_dns1 == "10.10.1.100"
+ - zone.internal_dns2 == "10.10.1.101"
+ - zone.local_storage_enabled == true
+ - zone.network_type == "Basic"
+ - zone.zone_token != ""
+ - zone.securitygroups_enabled == true
+ - zone.dhcp_provider == "VirtualRouter"
+
+- name: test update zone idempotency
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ internal_dns1: 10.10.1.100
+ internal_dns2: 10.10.1.101
+ local_storage_enabled: true
+ network_type: Basic
+ register: zone
+- name: verify test update zone idempotency
+ assert:
+ that:
+ - zone is successful
+ - zone is not changed
+ - zone.dns1 == "8.8.8.8"
+ - zone.dns2 == "8.8.4.4"
+ - zone.internal_dns1 == "10.10.1.100"
+ - zone.internal_dns2 == "10.10.1.101"
+ - zone.local_storage_enabled == true
+ - zone.network_type == "Basic"
+ - zone.zone_token != ""
+ - zone.securitygroups_enabled == true
+ - zone.dhcp_provider == "VirtualRouter"
+
+- name: test absent zone in check mode
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: zone
+ check_mode: true
+- name: verify test absent zone in check mode
+ assert:
+ that:
+ - zone is successful
+ - zone is changed
+ - zone.dns1 == "8.8.8.8"
+ - zone.dns2 == "8.8.4.4"
+ - zone.internal_dns1 == "10.10.1.100"
+ - zone.internal_dns2 == "10.10.1.101"
+ - zone.local_storage_enabled == true
+ - zone.network_type == "Basic"
+ - zone.zone_token != ""
+ - zone.securitygroups_enabled == true
+
+- name: test absent zone
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: zone
+- name: verify test absent zone
+ assert:
+ that:
+ - zone is successful
+ - zone is changed
+ - zone.dns1 == "8.8.8.8"
+ - zone.dns2 == "8.8.4.4"
+ - zone.internal_dns1 == "10.10.1.100"
+ - zone.internal_dns2 == "10.10.1.101"
+ - zone.local_storage_enabled == true
+ - zone.network_type == "Basic"
+ - zone.zone_token != ""
+ - zone.securitygroups_enabled == true
+
+- name: test absent zone idempotency
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ state: absent
+ register: zone
+- name: verify test absent zone idempotency
+ assert:
+ that:
+ - zone is successful
+ - zone is not changed
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/aliases
new file mode 100644
index 00000000..3b5a38e7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/aliases
@@ -0,0 +1,3 @@
+cloud/cs
+shippable/cs/group2
+shippable/cs/smoketest
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/meta/main.yml
new file mode 100644
index 00000000..e9a5b9ee
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - cs_common
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/tasks/main.yml
new file mode 100644
index 00000000..74dccf80
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/tasks/main.yml
@@ -0,0 +1,73 @@
+---
+- name: setup zone is present
+ cs_zone:
+ name: "{{ cs_resource_prefix }}-zone"
+ dns1: 8.8.8.8
+ dns2: 8.8.4.4
+ network_type: Basic
+ register: zone
+- name: verify setup zone is present
+ assert:
+ that:
+ - zone is successful
+
+- name: get info from zone in check mode
+ cs_zone_info:
+ name: "{{ cs_resource_prefix }}-zone"
+ register: zone
+ check_mode: yes
+- name: verify get info from zone in check mode
+ assert:
+ that:
+ - zone is successful
+ - zone is not changed
+ - zone.zones[0].dns1 == "8.8.8.8"
+ - zone.zones[0].dns2 == "8.8.4.4"
+ - zone.zones[0].internal_dns1 == "8.8.8.8"
+ - zone.zones[0].internal_dns2 == "8.8.4.4"
+ - zone.zones[0].local_storage_enabled == false
+ - zone.zones[0].network_type == "Basic"
+ - zone.zones[0].zone_token != ""
+ - zone.zones[0].securitygroups_enabled == true
+ - zone.zones[0].dhcp_provider == "VirtualRouter"
+ - zone.zones[0].local_storage_enabled == false
+
+- name: get info from zone
+ cs_zone_info:
+ name: "{{ cs_resource_prefix }}-zone"
+ register: zone
+- name: verify get info from zone
+ assert:
+ that:
+ - zone is successful
+ - zone is not changed
+ - zone.zones[0].dns1 == "8.8.8.8"
+ - zone.zones[0].dns2 == "8.8.4.4"
+ - zone.zones[0].internal_dns1 == "8.8.8.8"
+ - zone.zones[0].internal_dns2 == "8.8.4.4"
+ - zone.zones[0].local_storage_enabled == false
+ - zone.zones[0].network_type == "Basic"
+ - zone.zones[0].zone_token != ""
+ - zone.zones[0].securitygroups_enabled == true
+ - zone.zones[0].dhcp_provider == "VirtualRouter"
+ - zone.zones[0].local_storage_enabled == false
+
+- name: get info from all zones
+ cs_zone_info:
+ register: zones
+- name: verify get info from all zones
+ assert:
+ that:
+ - zones is successful
+ - zones is not changed
+ - zones.zones | length > 0
+ - '"dns1" in zone.zones[0]'
+ - '"dns2" in zone.zones[0]'
+ - '"internal_dns1" in zone.zones[0]'
+ - '"internal_dns2" in zone.zones[0]'
+ - '"local_storage_enabled" in zone.zones[0]'
+ - '"network_type" in zone.zones[0]'
+ - '"zone_token" in zone.zones[0]'
+ - '"securitygroups_enabled" in zone.zones[0]'
+ - '"dhcp_provider" in zone.zones[0]'
+ - '"local_storage_enabled" in zone.zones[0]'
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.10.txt b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.10.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.10.txt
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.9.txt b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.9.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.9.txt
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/requirements.txt b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/requirements.txt
new file mode 100644
index 00000000..3e3a9669
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/requirements.txt
@@ -0,0 +1,4 @@
+packaging # needed for update-bundled and changelog
+sphinx ; python_version >= '3.5' # docs build requires python 3+
+sphinx-notfound-page ; python_version >= '3.5' # docs build requires python 3+
+straight.plugin ; python_version >= '3.5' # needed for hacking/build-ansible.py which will host changelog generation and requires python 3+
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/unit/modules/test_cs_traffic_type.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/unit/modules/test_cs_traffic_type.py
new file mode 100644
index 00000000..0747b7ad
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/unit/modules/test_cs_traffic_type.py
@@ -0,0 +1,135 @@
+from __future__ import (absolute_import, division, print_function)
+import sys
+import pytest
+import units.compat.unittest as unittest
+from units.compat.mock import MagicMock
+from units.compat.unittest import TestCase
+from units.modules.utils import set_module_args
+
+__metaclass__ = type
+
+
+# Exoscale's cs doesn't support Python 2.6
+pytestmark = []
+if sys.version_info[:2] != (2, 6):
+ from ansible.modules.cloud.cloudstack.cs_traffic_type import AnsibleCloudStackTrafficType, setup_module_object
+ from ansible.module_utils.cloudstack import HAS_LIB_CS
+ if not HAS_LIB_CS:
+ pytestmark.append(pytest.mark.skip('The cloudstack library, "cs", is needed to test cs_traffic_type'))
+else:
+ pytestmark.append(pytest.mark.skip('Exoscale\'s cs doesn\'t support Python 2.6'))
+
+
+EXISTING_TRAFFIC_TYPES_RESPONSE = {
+ "count": 3,
+ "traffictype": [
+ {
+ "id": "9801cf73-5a73-4883-97e4-fa20c129226f",
+ "kvmnetworklabel": "cloudbr0",
+ "physicalnetworkid": "659c1840-9374-440d-a412-55ca360c9d3c",
+ "traffictype": "Management"
+ },
+ {
+ "id": "28ed70b7-9a1f-41bf-94c3-53a9f22da8b6",
+ "kvmnetworklabel": "cloudbr0",
+ "physicalnetworkid": "659c1840-9374-440d-a412-55ca360c9d3c",
+ "traffictype": "Guest"
+ },
+ {
+ "id": "9c05c802-84c0-4eda-8f0a-f681364ffb46",
+ "kvmnetworklabel": "cloudbr0",
+ "physicalnetworkid": "659c1840-9374-440d-a412-55ca360c9d3c",
+ "traffictype": "Storage"
+ }
+ ]
+}
+
+VALID_LIST_NETWORKS_RESPONSE = {
+ "count": 1,
+ "physicalnetwork": [
+ {
+ "broadcastdomainrange": "ZONE",
+ "id": "659c1840-9374-440d-a412-55ca360c9d3c",
+ "name": "eth1",
+ "state": "Enabled",
+ "vlan": "3900-4000",
+ "zoneid": "49acf813-a8dd-4da0-aa53-1d826d6003e7"
+ }
+ ]
+}
+
+VALID_LIST_ZONES_RESPONSE = {
+ "count": 1,
+ "zone": [
+ {
+ "allocationstate": "Enabled",
+ "dhcpprovider": "VirtualRouter",
+ "dns1": "8.8.8.8",
+ "dns2": "8.8.4.4",
+ "guestcidraddress": "10.10.0.0/16",
+ "id": "49acf813-a8dd-4da0-aa53-1d826d6003e7",
+ "internaldns1": "192.168.56.1",
+ "localstorageenabled": True,
+ "name": "DevCloud-01",
+ "networktype": "Advanced",
+ "securitygroupsenabled": False,
+ "tags": [],
+ "zonetoken": "df20d65a-c6c8-3880-9064-4f77de2291ef"
+ }
+ ]
+}
+
+
+base_module_args = {
+ "api_key": "api_key",
+ "api_secret": "very_secret_content",
+ "api_url": "http://localhost:8888/api/client",
+ "kvm_networklabel": "cloudbr0",
+ "physical_network": "eth1",
+ "poll_async": True,
+ "state": "present",
+ "traffic_type": "Guest",
+ "zone": "DevCloud-01"
+}
+
+
+class TestAnsibleCloudstackTraffiType(TestCase):
+
+ def test_module_is_created_sensibly(self):
+ set_module_args(base_module_args)
+ module = setup_module_object()
+ assert module.params['traffic_type'] == 'Guest'
+
+ def test_update_called_when_traffic_type_exists(self):
+ set_module_args(base_module_args)
+ module = setup_module_object()
+ actt = AnsibleCloudStackTrafficType(module)
+ actt.get_traffic_type = MagicMock(return_value=EXISTING_TRAFFIC_TYPES_RESPONSE['traffictype'][0])
+ actt.update_traffic_type = MagicMock()
+ actt.present_traffic_type()
+ self.assertTrue(actt.update_traffic_type.called)
+
+ def test_update_not_called_when_traffic_type_doesnt_exist(self):
+ set_module_args(base_module_args)
+ module = setup_module_object()
+ actt = AnsibleCloudStackTrafficType(module)
+ actt.get_traffic_type = MagicMock(return_value=None)
+ actt.update_traffic_type = MagicMock()
+ actt.add_traffic_type = MagicMock()
+ actt.present_traffic_type()
+ self.assertFalse(actt.update_traffic_type.called)
+ self.assertTrue(actt.add_traffic_type.called)
+
+ def test_traffic_type_returned_if_exists(self):
+ set_module_args(base_module_args)
+ module = setup_module_object()
+ actt = AnsibleCloudStackTrafficType(module)
+ actt.get_physical_network = MagicMock(return_value=VALID_LIST_NETWORKS_RESPONSE['physicalnetwork'][0])
+ actt.get_traffic_types = MagicMock(return_value=EXISTING_TRAFFIC_TYPES_RESPONSE)
+ tt = actt.present_traffic_type()
+ self.assertTrue(tt.get('kvmnetworklabel') == base_module_args['kvm_networklabel'])
+ self.assertTrue(tt.get('traffictype') == base_module_args['traffic_type'])
+
+
+if __name__ == '__main__':
+ unittest.main()