From 02c9c5bca1418779d601962b58e384cf8cb290fb Mon Sep 17 00:00:00 2001 From: Pradeepsingh Bhati Date: Fri, 29 Jul 2022 09:34:33 +0530 Subject: [PATCH] Feat/1.4 (#248) * Feat/hosts and cluseters info modules (#231) Info modules for hosts and clusters info Co-authored-by: Gevorg-Khachatryaan Co-authored-by: alaa-bish Co-authored-by: Pradeepsingh Bhati * fix hosts and clusters * Module for PC categories (#236) Module for categories Co-authored-by: alaa-bish * Module for users (#246) Users module Co-authored-by: Gevorg-Khachatryaan Co-authored-by: Pradeepsingh Bhati * Module for Service Groups (#242) Service groups module Co-authored-by: Gevorg-Khachatryaan Co-authored-by: alaa-bish * Module for user groups (#245) User group module Co-authored-by: Gevorg-Khachatryaan Co-authored-by: Pradeepsingh Bhati * Feat/access control policies (#238) ACP modules Co-authored-by: Gevorg-Khachatryaan Co-authored-by: alaa-bish Co-authored-by: Pradeepsingh Bhati * New modules for Projects, Projects Info, Users Info and User Groups info (#237) Modules for projects, users info and user groups info Co-authored-by: alaa-bish * fix filter examples (#227) * Permissions, Address Groups and Roles modules (#243) * Permissions module * Add meta runtime changes * Roles module * Info module for roles and minor fixes * Address groups module * Minor typo fixes * Test for roles * tests for address groups * Minor fix and formatting * Change subnet_details to subnets for address groups * roles docs * Add examples and docs * Fix info tests * Doc fix * Examples of projects and categories * Minor change * runtime changes * Var changes * skip dest create * fix tests * Minor fix * add examples * Remove quarantine uuid * sanity fix * Skip some tests * Revert disabled tests * Unskip more tests * Remove debug statements * remove debug from categoris * fix image tests * roles test fix * fix readme * Fix static routes test * Formatting * enable static routes * Minor fix * Skip project with cluster tests. IDP and OU related tests for users and user groups (#249) Co-authored-by: Gevorg-Khachatryaan * Skip image upload tests * update vlan ids * Read me changes * Update docs * Minor fixes and update ansible version * Fix lint * Change Log update * minor update * Minor fix * Minor changes * Minor fix * Fix sanity * Formatting * Fix sanity * Ansible version revert * Ansible version changes * readme changes * Class name changes entitiy modules * Static routes minor fix Co-authored-by: Gevorg Khachatryan <95351366+Gevorg-Khachatryan-97@users.noreply.github.com> Co-authored-by: alaa-bish --- CHANGELOG.md | 30 ++ README.md | 36 +- examples/acp.yml | 47 ++ examples/acp_info.yml | 31 ++ examples/address_groups_crud.yml | 51 ++ examples/category_crud.yml | 74 +++ examples/clusters_info.yml | 30 ++ examples/fip_info.yml | 3 +- examples/hosts_info.yml | 31 ++ examples/permissions_info.yml | 32 ++ examples/projects_crud.yml | 58 +++ examples/roles_crud.yml | 52 ++ examples/subnet_info.yml | 3 +- examples/user-groups.yml | 50 ++ examples/user.yml | 61 +++ examples/vm_info.yml | 3 +- examples/vpc_info.yml | 3 +- galaxy.yml | 2 +- meta/runtime.yml | 22 + plugins/module_utils/entity.py | 22 +- plugins/module_utils/prism/acps.py | 104 ++++ plugins/module_utils/prism/address_groups.py | 35 +- plugins/module_utils/prism/categories.py | 86 ++++ plugins/module_utils/prism/clusters.py | 7 + plugins/module_utils/prism/groups.py | 8 +- plugins/module_utils/prism/hosts.py | 13 + plugins/module_utils/prism/permissions.py | 62 +++ plugins/module_utils/prism/projects.py | 99 ++++ plugins/module_utils/prism/roles.py | 65 +++ plugins/module_utils/prism/service_groups.py | 70 ++- plugins/module_utils/prism/static_routes.py | 4 +- plugins/module_utils/prism/subnets.py | 7 + plugins/module_utils/prism/user_groups.py | 62 +++ plugins/module_utils/prism/users.py | 94 +++- plugins/module_utils/utils.py | 14 +- plugins/modules/ntnx_acps.py | 474 ++++++++++++++++++ plugins/modules/ntnx_acps_info.py | 250 +++++++++ plugins/modules/ntnx_address_groups.py | 236 +++++++++ plugins/modules/ntnx_address_groups_info.py | 156 ++++++ plugins/modules/ntnx_categories.py | 318 ++++++++++++ plugins/modules/ntnx_categories_info.py | 164 ++++++ plugins/modules/ntnx_clusters_info.py | 245 +++++++++ plugins/modules/ntnx_floating_ips_info.py | 8 +- plugins/modules/ntnx_hosts_info.py | 206 ++++++++ .../modules/ntnx_image_placement_policy.py | 2 +- plugins/modules/ntnx_images.py | 2 +- plugins/modules/ntnx_pbrs_info.py | 3 +- plugins/modules/ntnx_permissions_info.py | 185 +++++++ plugins/modules/ntnx_projects.py | 394 +++++++++++++++ plugins/modules/ntnx_projects_info.py | 210 ++++++++ plugins/modules/ntnx_roles.py | 314 ++++++++++++ plugins/modules/ntnx_roles_info.py | 206 ++++++++ plugins/modules/ntnx_security_rules.py | 2 +- plugins/modules/ntnx_security_rules_info.py | 3 +- plugins/modules/ntnx_service_groups.py | 278 ++++++++++ plugins/modules/ntnx_service_groups_info.py | 198 ++++++++ plugins/modules/ntnx_static_routes.py | 33 +- plugins/modules/ntnx_static_routes_info.py | 4 +- plugins/modules/ntnx_subnets_info.py | 3 +- plugins/modules/ntnx_user_groups.py | 299 +++++++++++ plugins/modules/ntnx_user_groups_info.py | 228 +++++++++ plugins/modules/ntnx_users.py | 318 ++++++++++++ plugins/modules/ntnx_users_info.py | 213 ++++++++ plugins/modules/ntnx_vms.py | 2 +- plugins/modules/ntnx_vms_info.py | 3 +- plugins/modules/ntnx_vpcs_info.py | 3 +- tests/integration/targets/ntnx_acps/aliases | 1 + .../targets/ntnx_acps/meta/main.yml | 2 + .../targets/ntnx_acps/tasks/create_acps.yml | 187 +++++++ .../targets/ntnx_acps/tasks/delete_acp.yml | 62 +++ .../targets/ntnx_acps/tasks/main.yml | 12 + .../ntnx_acps/tasks/negative_scenarios.yml | 61 +++ .../targets/ntnx_acps/tasks/update_acps.yml | 105 ++++ .../targets/ntnx_acps_info/aliases | 0 .../targets/ntnx_acps_info/meta/main.yml | 2 + .../targets/ntnx_acps_info/tasks/info.yml | 56 +++ .../targets/ntnx_acps_info/tasks/main.yml | 9 + .../targets/ntnx_address_groups/aliases | 0 .../targets/ntnx_address_groups/meta/main.yml | 2 + .../ntnx_address_groups/tasks/create.yml | 97 ++++ .../ntnx_address_groups/tasks/delete.yml | 38 ++ .../ntnx_address_groups/tasks/main.yml | 11 + .../ntnx_address_groups/tasks/update.yml | 118 +++++ .../targets/ntnx_address_groups_info/aliases | 0 .../ntnx_address_groups_info/meta/main.yml | 2 + .../tasks/address_groups_info.yml | 111 ++++ .../ntnx_address_groups_info/tasks/main.yml | 9 + .../targets/ntnx_categories/aliases | 0 .../targets/ntnx_categories/meta/main.yml | 2 + .../ntnx_categories/tasks/all_operations.yml | 219 ++++++++ .../targets/ntnx_categories/tasks/main.yml | 9 + .../targets/ntnx_categories_info/aliases | 0 .../ntnx_categories_info/meta/main.yml | 2 + .../ntnx_categories_info/tasks/info.yml | 83 +++ .../ntnx_categories_info/tasks/main.yml | 9 + .../targets/ntnx_clusters_info/aliases | 0 .../targets/ntnx_clusters_info/meta/main.yml | 2 + .../tasks/get_clusters_info.yml | 55 ++ .../targets/ntnx_clusters_info/tasks/main.yml | 9 + .../targets/ntnx_hosts_info/aliases | 0 .../targets/ntnx_hosts_info/meta/main.yml | 2 + .../ntnx_hosts_info/tasks/get_hosts_info.yml | 55 ++ .../targets/ntnx_hosts_info/tasks/main.yml | 9 + .../aliases | 0 .../ntnx_image_placement_policy/aliases | 0 tests/integration/targets/ntnx_images/aliases | 0 .../targets/ntnx_images/tasks/create.yml | 4 +- .../targets/ntnx_images_info/aliases | 0 tests/integration/targets/ntnx_ova/aliases | 0 .../targets/ntnx_permissions_info/aliases | 0 .../ntnx_permissions_info/meta/main.yml | 2 + .../ntnx_permissions_info/tasks/main.yml | 9 + .../tasks/permissions_info.yml | 82 +++ .../targets/ntnx_projects/meta/main.yml | 2 + .../ntnx_projects/tasks/create_project.yml | 142 ++++++ .../ntnx_projects/tasks/delete_project.yml | 33 ++ .../targets/ntnx_projects/tasks/main.yml | 11 + .../ntnx_projects/tasks/update_project.yml | 150 ++++++ .../targets/ntnx_projects_info/meta/main.yml | 2 + .../targets/ntnx_projects_info/tasks/main.yml | 9 + .../tasks/projects_info.yml | 113 +++++ .../targets/ntnx_projects_info/vars/main.yml | 1 + tests/integration/targets/ntnx_roles/aliases | 0 .../targets/ntnx_roles/meta/main.yml | 2 + .../targets/ntnx_roles/tasks/create.yml | 112 +++++ .../targets/ntnx_roles/tasks/delete.yml | 48 ++ .../targets/ntnx_roles/tasks/main.yml | 11 + .../targets/ntnx_roles/tasks/update.yml | 125 +++++ .../targets/ntnx_roles_info/aliases | 0 .../targets/ntnx_roles_info/meta/main.yml | 2 + .../targets/ntnx_roles_info/tasks/main.yml | 9 + .../ntnx_roles_info/tasks/roles_info.yml | 82 +++ .../targets/ntnx_security_rules/aliases | 0 .../targets/ntnx_security_rules/vars/main.yml | 1 - .../targets/ntnx_security_rules_info/aliases | 0 .../targets/ntnx_service_groups/aliases | 0 .../targets/ntnx_service_groups/meta/main.yml | 2 + .../ntnx_service_groups/tasks/create.yml | 180 +++++++ .../ntnx_service_groups/tasks/main.yml | 10 + .../ntnx_service_groups/tasks/update.yml | 106 ++++ .../targets/ntnx_service_groups_info/aliases | 0 .../ntnx_service_groups_info/meta/main.yml | 2 + .../ntnx_service_groups_info/tasks/info.yml | 74 +++ .../ntnx_service_groups_info/tasks/main.yml | 9 + .../ntnx_static_routes/tasks/create.yml | 8 +- .../ntnx_static_routes_info/tasks/info.yml | 10 +- .../targets/ntnx_user_groups/aliases | 0 .../targets/ntnx_user_groups/meta/main.yml | 2 + .../targets/ntnx_user_groups/tasks/create.yml | 82 +++ .../targets/ntnx_user_groups/tasks/main.yml | 9 + .../targets/ntnx_user_groups_info/aliases | 0 .../ntnx_user_groups_info/meta/main.yml | 2 + .../ntnx_user_groups_info/tasks/info.yml | 78 +++ .../ntnx_user_groups_info/tasks/main.yml | 9 + .../tasks/user_groups_info.yml | 96 ++++ tests/integration/targets/ntnx_users/aliases | 0 .../targets/ntnx_users/meta/main.yml | 2 + .../targets/ntnx_users/tasks/create.yml | 184 +++++++ .../targets/ntnx_users/tasks/main.yml | 9 + .../targets/ntnx_users_info/aliases | 0 .../targets/ntnx_users_info/meta/main.yml | 2 + .../targets/ntnx_users_info/tasks/info.yml | 78 +++ .../targets/ntnx_users_info/tasks/main.yml | 9 + .../ntnx_users_info/tasks/users_info.yml | 96 ++++ .../targets/ntnx_vms_clone/vars/main.yml | 15 - .../tasks/list_floating_ips.yml | 10 +- .../nutanix_pbrs_info/tasks/list_pbrs.yml | 4 - .../targets/nutanix_subnets/vars/main.yml | 2 +- .../tasks/list_subnets.yml | 8 - .../targets/nutanix_vms/vars/main.yml | 15 - .../nutanix_vms_info/tasks/list_vms.yml | 7 - .../nutanix_vpcs_info/tasks/list_vpcs.yml | 8 - .../targets/prepare_env/tasks/prepare_env.yml | 9 + .../targets/prepare_env/vars/.gitkeep | 0 .../targets/prepare_env/vars/main.yml | 38 -- 175 files changed, 9619 insertions(+), 180 deletions(-) create mode 100644 examples/acp.yml create mode 100644 examples/acp_info.yml create mode 100644 examples/address_groups_crud.yml create mode 100644 examples/category_crud.yml create mode 100644 examples/clusters_info.yml create mode 100644 examples/hosts_info.yml create mode 100644 examples/permissions_info.yml create mode 100644 examples/projects_crud.yml create mode 100644 examples/roles_crud.yml create mode 100644 examples/user-groups.yml create mode 100644 examples/user.yml create mode 100644 plugins/module_utils/prism/acps.py create mode 100644 plugins/module_utils/prism/categories.py create mode 100644 plugins/module_utils/prism/hosts.py create mode 100644 plugins/module_utils/prism/permissions.py create mode 100644 plugins/module_utils/prism/roles.py create mode 100644 plugins/module_utils/prism/user_groups.py create mode 100644 plugins/modules/ntnx_acps.py create mode 100644 plugins/modules/ntnx_acps_info.py create mode 100644 plugins/modules/ntnx_address_groups.py create mode 100644 plugins/modules/ntnx_address_groups_info.py create mode 100644 plugins/modules/ntnx_categories.py create mode 100644 plugins/modules/ntnx_categories_info.py create mode 100644 plugins/modules/ntnx_clusters_info.py create mode 100644 plugins/modules/ntnx_hosts_info.py create mode 100644 plugins/modules/ntnx_permissions_info.py create mode 100644 plugins/modules/ntnx_projects.py create mode 100644 plugins/modules/ntnx_projects_info.py create mode 100644 plugins/modules/ntnx_roles.py create mode 100644 plugins/modules/ntnx_roles_info.py create mode 100644 plugins/modules/ntnx_service_groups.py create mode 100644 plugins/modules/ntnx_service_groups_info.py create mode 100644 plugins/modules/ntnx_user_groups.py create mode 100644 plugins/modules/ntnx_user_groups_info.py create mode 100644 plugins/modules/ntnx_users.py create mode 100644 plugins/modules/ntnx_users_info.py create mode 100644 tests/integration/targets/ntnx_acps/aliases create mode 100644 tests/integration/targets/ntnx_acps/meta/main.yml create mode 100644 tests/integration/targets/ntnx_acps/tasks/create_acps.yml create mode 100644 tests/integration/targets/ntnx_acps/tasks/delete_acp.yml create mode 100644 tests/integration/targets/ntnx_acps/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_acps/tasks/negative_scenarios.yml create mode 100644 tests/integration/targets/ntnx_acps/tasks/update_acps.yml create mode 100644 tests/integration/targets/ntnx_acps_info/aliases create mode 100644 tests/integration/targets/ntnx_acps_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_acps_info/tasks/info.yml create mode 100644 tests/integration/targets/ntnx_acps_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_address_groups/aliases create mode 100644 tests/integration/targets/ntnx_address_groups/meta/main.yml create mode 100644 tests/integration/targets/ntnx_address_groups/tasks/create.yml create mode 100644 tests/integration/targets/ntnx_address_groups/tasks/delete.yml create mode 100644 tests/integration/targets/ntnx_address_groups/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_address_groups/tasks/update.yml create mode 100644 tests/integration/targets/ntnx_address_groups_info/aliases create mode 100644 tests/integration/targets/ntnx_address_groups_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_address_groups_info/tasks/address_groups_info.yml create mode 100644 tests/integration/targets/ntnx_address_groups_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_categories/aliases create mode 100644 tests/integration/targets/ntnx_categories/meta/main.yml create mode 100644 tests/integration/targets/ntnx_categories/tasks/all_operations.yml create mode 100644 tests/integration/targets/ntnx_categories/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_categories_info/aliases create mode 100644 tests/integration/targets/ntnx_categories_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_categories_info/tasks/info.yml create mode 100644 tests/integration/targets/ntnx_categories_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_clusters_info/aliases create mode 100644 tests/integration/targets/ntnx_clusters_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_clusters_info/tasks/get_clusters_info.yml create mode 100644 tests/integration/targets/ntnx_clusters_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_hosts_info/aliases create mode 100644 tests/integration/targets/ntnx_hosts_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_hosts_info/tasks/get_hosts_info.yml create mode 100644 tests/integration/targets/ntnx_hosts_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_image_placement_policies_info/aliases create mode 100644 tests/integration/targets/ntnx_image_placement_policy/aliases create mode 100644 tests/integration/targets/ntnx_images/aliases create mode 100644 tests/integration/targets/ntnx_images_info/aliases create mode 100644 tests/integration/targets/ntnx_ova/aliases create mode 100644 tests/integration/targets/ntnx_permissions_info/aliases create mode 100644 tests/integration/targets/ntnx_permissions_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_permissions_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_permissions_info/tasks/permissions_info.yml create mode 100644 tests/integration/targets/ntnx_projects/meta/main.yml create mode 100644 tests/integration/targets/ntnx_projects/tasks/create_project.yml create mode 100644 tests/integration/targets/ntnx_projects/tasks/delete_project.yml create mode 100644 tests/integration/targets/ntnx_projects/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_projects/tasks/update_project.yml create mode 100644 tests/integration/targets/ntnx_projects_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_projects_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_projects_info/tasks/projects_info.yml create mode 100644 tests/integration/targets/ntnx_projects_info/vars/main.yml create mode 100644 tests/integration/targets/ntnx_roles/aliases create mode 100644 tests/integration/targets/ntnx_roles/meta/main.yml create mode 100644 tests/integration/targets/ntnx_roles/tasks/create.yml create mode 100644 tests/integration/targets/ntnx_roles/tasks/delete.yml create mode 100644 tests/integration/targets/ntnx_roles/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_roles/tasks/update.yml create mode 100644 tests/integration/targets/ntnx_roles_info/aliases create mode 100644 tests/integration/targets/ntnx_roles_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_roles_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_roles_info/tasks/roles_info.yml create mode 100644 tests/integration/targets/ntnx_security_rules/aliases delete mode 100644 tests/integration/targets/ntnx_security_rules/vars/main.yml create mode 100644 tests/integration/targets/ntnx_security_rules_info/aliases create mode 100644 tests/integration/targets/ntnx_service_groups/aliases create mode 100644 tests/integration/targets/ntnx_service_groups/meta/main.yml create mode 100644 tests/integration/targets/ntnx_service_groups/tasks/create.yml create mode 100644 tests/integration/targets/ntnx_service_groups/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_service_groups/tasks/update.yml create mode 100644 tests/integration/targets/ntnx_service_groups_info/aliases create mode 100644 tests/integration/targets/ntnx_service_groups_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_service_groups_info/tasks/info.yml create mode 100644 tests/integration/targets/ntnx_service_groups_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_user_groups/aliases create mode 100644 tests/integration/targets/ntnx_user_groups/meta/main.yml create mode 100644 tests/integration/targets/ntnx_user_groups/tasks/create.yml create mode 100644 tests/integration/targets/ntnx_user_groups/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_user_groups_info/aliases create mode 100644 tests/integration/targets/ntnx_user_groups_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_user_groups_info/tasks/info.yml create mode 100644 tests/integration/targets/ntnx_user_groups_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_user_groups_info/tasks/user_groups_info.yml create mode 100644 tests/integration/targets/ntnx_users/aliases create mode 100644 tests/integration/targets/ntnx_users/meta/main.yml create mode 100644 tests/integration/targets/ntnx_users/tasks/create.yml create mode 100644 tests/integration/targets/ntnx_users/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_users_info/aliases create mode 100644 tests/integration/targets/ntnx_users_info/meta/main.yml create mode 100644 tests/integration/targets/ntnx_users_info/tasks/info.yml create mode 100644 tests/integration/targets/ntnx_users_info/tasks/main.yml create mode 100644 tests/integration/targets/ntnx_users_info/tasks/users_info.yml delete mode 100644 tests/integration/targets/ntnx_vms_clone/vars/main.yml delete mode 100644 tests/integration/targets/nutanix_vms/vars/main.yml create mode 100644 tests/integration/targets/prepare_env/vars/.gitkeep diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fb890f76..12bb71691 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,33 @@ +## v1.4.0 (28 July 2022) + +**Features** + +**Prism Central** +- Ansible module for Access Control Policy (ACPs) +- Ansible info module for Access Control Policy (ACPs) +- Ansible module for Projects +- Ansible info module for Projects +- Ansible module for Roles +- Ansible info module for Roles +- Ansible info module for Permissions +- Ansible module for Categories +- Ansible info module for Categories +- Ansible module for Address Groups +- Ansible info module for Address Groups +- Ansible module for Service Groups +- Ansible info module for Service Groups +- Ansible module for Users +- Ansible info module for Users +- Ansible module for User Groups +- Ansible info module for User Groups +- Ansible info module for Hosts +- Ansible info module for Clusters + +**Bugs** +- Fix examples of info modules [\#226](https://github.com/nutanix/nutanix.ansible/issues/226) + +**Full Changelog:** [here](https://github.com/nutanix/nutanix.ansible/compare/v1.3.0...v1.4.0) + ## v1.3.0 (4 July 2022) **Features** diff --git a/README.md b/README.md index d77a41df4..135e1d525 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,28 @@ It is designed keeping simplicity as the core value. Hence it is # Version compatibility ## Ansible -> This collection has been tested against following Ansible versions: >=2.12.2. +> This collection has been tested against following versions: + 1. ansible==5.0.1 + 2. ansible-core==2.12.3 ## Python > This collection requires Python 2.7 or greater ## Prism Cenral > For the 1.1.0 release of the ansible plugin it will have N-2 compatibility with the Prism Central APIs. This release was tested against Prism Central versions pc2022.1.0.2, pc.2021.9.0.5 and pc.2021.8.0.1. + > For the 1.2.0 release of the ansible plugin it will have N-2 compatibility with the Prism Central APIs. This release was tested against Prism Central versions pc.2022.4, pc2022.1.0.2 and pc.2021.9.0.5. -> For the 1.3.0 release of the ansible plugin it will have N-2 compatibility with the Prism Central APIs. This release was tested against Prism Central versions pc.2022.4, pc2022.1.0.2 and pc.2021.9.0.4. Static routes module (ntnx_static_routes) is only supported for PC versions >= pc.2022.1. + +> For the 1.3.0 release of the ansible plugin it will have N-2 compatibility with the Prism Central APIs. This release was tested against Prism Central versions pc.2022.4, pc2022.1.0.2 and pc.2021.9.0.4. + +> For the 1.4.0 release of the ansible plugin it will have N-2 compatibility with the Prism Central APIs. This release was tested against Prism Central versions pc.2022.4, pc2022.1.0.2 and pc.2021.9.0.4. + +### Notes: +1. Static routes module (ntnx_static_routes) is supported for PC versions >= pc.2022.1 + +2. Adding cluster references in projects module (ntnx_projects) is supported for PC versions >= pc.2022.1 + +3. For Users and User Groups modules (ntnx_users and ntnx_user_groups), adding Identity Provider (IdP) & Organizational Unit (OU) based users/groups are supported for PC versions >= pc.2022.1 Prism Central based examples: https://github.com/nutanix/nutanix.ansible/tree/main/examples/ @@ -99,16 +112,31 @@ ansible-playbook examples/iaas/iaas.yml | Name | Description | | --- | --- | +| ntnx_acps | Create, Update, Delete acp. | +| ntnx_acps_info | Get acp info. | +| ntnx_address_groups | Create, Update, Delete Nutanix address groups. | +| ntnx_address_groups_info | Get address groups info. | +| ntnx_categories | Create, Update, Delete categories | +| ntnx_categories_info | Get categories info. | +| ntnx_clusters_info | Get cluster info. | | ntnx_floating_ips | Create or delete a Floating Ip. | | ntnx_floating_ips_info | List existing Floating_Ips. | +| ntnx_hosts_info | Get host info. | | ntnx_images | Create, update or delete a image. | | ntnx_images_info | List existing images. | | ntnx_image_placement_policy | Create, update or delete a image placement policy. | | ntnx_image_placement_policies_info | List existing image placement policies. | | ntnx_pbrs | Create or delete a PBR. | | ntnx_pbrs_info | List existing PBRs. | +| ntnx_permissions_info | List permissions info | +| ntnx_projects | create, update and delete pc projects | +| ntnx_projects_info | Get projects info. | +| ntnx_roles | Create, Update, Delete Nutanix roles | +| ntnx_roles_info | Get roles info. | | ntnx_security_rules | Create, update or delete a Security Rule. | | ntnx_security_rules_info | List existing Security Rules. | +| ntnx_service_groups | Create, Update, Delete service_group | +| ntnx_service_groups_info | Get service groups info. | | ntnx_static_routes | Update static routes of a vpc. | | ntnx_static_routes_info | List existing static routes of a vpc. | | ntnx_subnets | Create or delete a Subnet. | @@ -131,6 +159,10 @@ ansible-playbook examples/iaas/iaas.yml | ntnx_foundation_central_api_keys_info | List all the api keys created in Foundation Central. | | ntnx_foundation_central_imaged_clusters_info | List all the clusters created using Foundation Central. | | ntnx_foundation_central_imaged_nodes_info | List all the nodes registered with Foundation Central. | +| ntnx_user_groups | Create, Delete user_groups | +| ntnx_user_groups_info | Get user groups info. | +| ntnx_users | Create, Delete users | +| ntnx_users_info | Get users info. | ## Inventory Plugins diff --git a/examples/acp.yml b/examples/acp.yml new file mode 100644 index 000000000..a3375dacd --- /dev/null +++ b/examples/acp.yml @@ -0,0 +1,47 @@ +--- +- name: ACP playbook + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + + tasks: + + - name: Create ACP with all specfactions + ntnx_acps: + validate_certs: False + state: present + nutanix_host: "{{ IP }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + name: acp_with_all_specfactions + role: + uuid: "{{ role.uuid }}" + user_uuids: + - "{{ user_uuid }}" + user_group_uuids: + - "{{ user_group_uuid }}" + filters: + - scope_filter: + lhs: PROJECT + operator: IN + rhs: + uuid_list: + - "{{ project.uuid }}" + entity_filter: + lhs: ALL + operator: IN + rhs: + collection: ALL + + - name: Delete ACP + ntnx_acps: + state: absent + acp_uuid: "{{ acp_uuid }}" + register: result diff --git a/examples/acp_info.yml b/examples/acp_info.yml new file mode 100644 index 000000000..acd1547dd --- /dev/null +++ b/examples/acp_info.yml @@ -0,0 +1,31 @@ +--- +- name: ACP_Info playbook + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + + tasks: + + - name: List ACPs using ascending, sorting and name filter + ntnx_floating_ips_info: + filter: + name: "{{ acp_name }}" + kind: access_control_policy + sort_order: "ASCENDING" + sort_attribute: "name" + register: result + ignore_errors: True + + - name: List ACPs using length and offset + ntnx_floating_ips_info: + length: 3 + offset: 0 + register: result + ignore_errors: True diff --git a/examples/address_groups_crud.yml b/examples/address_groups_crud.yml new file mode 100644 index 000000000..10d825f1c --- /dev/null +++ b/examples/address_groups_crud.yml @@ -0,0 +1,51 @@ +- name: Address group crud playbook. Here we will create, update, read and delete the address group. + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + tasks: + - name: Create a address group + ntnx_address_groups: + state: present + name: test-ansible-group-1 + desc: test-ansible-group-1-desc + subnets: + - network_ip: "10.1.1.0" + network_prefix: 24 + - network_ip: "10.1.2.2" + network_prefix: 32 + register: ag + + - name: update address group + ntnx_address_groups: + state: present + address_group_uuid: "{{ag.address_group_uuid}}" + name: test-ansible-group-1-updated + desc: test-ansible-group-1-desc-updated + subnets: + - network_ip: "10.1.3.0" + network_prefix: 24 + register: updated_ag + + - name: Read the updated address group + ntnx_address_groups_info: + address_group_uuid: "{{updated_ag.address_group_uuid}}" + register: ag_info + + - name: Print the address group details + debug: + msg: "{{ag_info}}" + + - name: Delete the address group. + ntnx_address_groups: + state: absent + address_group_uuid: "{{updated_ag.address_group_uuid}}" + register: op + + \ No newline at end of file diff --git a/examples/category_crud.yml b/examples/category_crud.yml new file mode 100644 index 000000000..5bab0cfc5 --- /dev/null +++ b/examples/category_crud.yml @@ -0,0 +1,74 @@ +- name: categories crud playbook. Here we will create, update, read and delete the category key values. + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + tasks: + - name: Create only category key with description + ntnx_categories: + state: "present" + name: "test-cat-1" + desc: "test-cat-1-desc" + register: cat1 + + - name: Add category values to test-cat-1 + ntnx_categories: + state: "present" + name: "test-cat-1" + values: + - "val1" + - "val2" + + - name: Create category key with values + ntnx_categories: + state: "present" + name: "test-cat-2" + desc: "test-cat-2-desc" + values: + - "val3" + - "val4" + register: cat2 + + - name: Add more category values to test-cat-2 + ntnx_categories: + state: "present" + name: "test-cat-2" + values: + - "val5" + - "val6" + + - name: Get categories info + ntnx_categories_info: + name: "test-cat-1" + register: cat1_info + + - name: Delete val1 category value from test-cat-1 + ntnx_categories: + state: absent + name: "test-cat-1" + values: + - val1 + + - name: delete all category values from test-cat-1 + ntnx_categories: + state: absent + name: "test-cat-1" + remove_values: true + + - name: delete category key test-cat-2 including its all values + ntnx_categories: + state: absent + name: "test-cat-2" + remove_values: true + + + + + + \ No newline at end of file diff --git a/examples/clusters_info.yml b/examples/clusters_info.yml new file mode 100644 index 000000000..0e7d9d868 --- /dev/null +++ b/examples/clusters_info.yml @@ -0,0 +1,30 @@ +--- +- name: Clusters_Info playbook + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + + tasks: + - name: test getting all clusters + ntnx_clusters_info: + register: clusters + + - name: test getting particular cluster using uuid + ntnx_clusters_info: + cluster_uuid: '{{ clusters.response.entities[0].metadata.uuid }}' + register: result + + - name: List clusters using length, offset, sort order and priority sort attribute + ntnx_clusters_info: + length: 2 + offset: 0 + sort_order: "ASCENDING" + sort_attribute: "name" + register: result diff --git a/examples/fip_info.yml b/examples/fip_info.yml index 9f954026d..15573d420 100644 --- a/examples/fip_info.yml +++ b/examples/fip_info.yml @@ -15,7 +15,8 @@ - name: List floating_ips using ascending ip sorting and floating_ip filter ntnx_floating_ips_info: - filter: "floating_ip==10." + filter: + floating_ip: "10.0.1.2" kind: floating_ip sort_order: "ASCENDING" sort_attribute: "floating_ip" diff --git a/examples/hosts_info.yml b/examples/hosts_info.yml new file mode 100644 index 000000000..fcf3405e1 --- /dev/null +++ b/examples/hosts_info.yml @@ -0,0 +1,31 @@ +--- +- name: Hosts_Info playbook + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + + tasks: + - name: test getting all hosts + ntnx_hosts_info: + register: hosts + + - name: test getting particular host using uuid + ntnx_hosts_info: + host_uuid: '{{ hosts.response.entities[0].metadata.uuid }}' + register: result + + - name: List hosts using length, offset, sort order and name sort attribute + ntnx_hosts_info: + length: 2 + offset: 0 + sort_order: "ASCENDING" + sort_attribute: "name" + register: result + ignore_errors: True diff --git a/examples/permissions_info.yml b/examples/permissions_info.yml new file mode 100644 index 000000000..a8d923920 --- /dev/null +++ b/examples/permissions_info.yml @@ -0,0 +1,32 @@ +########## Permissions Info Module Examples ################################ +- name: PC permissions + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "" + nutanix_username: "" + nutanix_password: "" + validate_certs: false + + tasks: + - name: get all permissions + ntnx_permissions_info: + register: op1 + + - name: get permissions using filter + ntnx_permissions_info: + filter: + name: + register: op2 + + - name: get permission using uuid + ntnx_permissions_info: + permission_uuid: + register: op3 + + - name: output + debug: + msg: "{{ op3 }}" \ No newline at end of file diff --git a/examples/projects_crud.yml b/examples/projects_crud.yml new file mode 100644 index 000000000..61dc67c37 --- /dev/null +++ b/examples/projects_crud.yml @@ -0,0 +1,58 @@ +- name: projects crud playbook. Here we will create, update, read and delete the project. + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + tasks: + - name: Create a project + ntnx_projects: + name: "test-ansible-project-1" + desc: "desc-123" + subnets: + - name: "s1" + default_subnet: + name: "s1" + users: + - "" + external_user_groups: + - "" + resource_limits: + - resource_type: STORAGE + limit: 2046000 + register: project1 + + - name: update project + ntnx_projects: + state: present + project_uuid: "{{project1.project_uuid}}" + name: "test-ansible-project-1" + desc: "test-ansible-project-1-updated" + resource_limits: + - resource_type: STORAGE + limit: 4096000 + - resource_type: MEMORY + limit: 4096000 + register: updated_project + + - name: Read the updated project + ntnx_projects_info: + project_uuid: "{{updated_project.project_uuid}}" + register: project_info + + - name: Print the project details + debug: + msg: "{{project_info}}" + + - name: Delete the project + ntnx_projects: + state: absent + project_uuid: "{{updated_project.project_uuid}}" + register: op + + \ No newline at end of file diff --git a/examples/roles_crud.yml b/examples/roles_crud.yml new file mode 100644 index 000000000..4f13a031f --- /dev/null +++ b/examples/roles_crud.yml @@ -0,0 +1,52 @@ +- name: Roles crud playbook. Here we will create, update, read and delete the role. + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + tasks: + - name: get some permissions for adding in roles + ntnx_permissions_info: + register: permissions + + - name: Create a role with 2 permissions. Here we will be using name or uuid for referenceing permissions + ntnx_roles: + state: present + name: test-ansible-role-1 + desc: + permissions: + - name: "{{ permissions.response.entities[0].status.name }}" + - uuid: "{{ permissions.response.entities[1].metadata.uuid }}" + wait: true + register: role1 + + - name: Update role + ntnx_roles: + state: present + role_uuid: "{{ role1.role_uuid }}" + name: test-ansible-role-1 + permissions: + - name: "{{ permissions.response.entities[2].status.name }}" + wait: true + register: updated_role1 + + - name: Read the updated role + ntnx_roles_info: + role_uuid: "{{ updated_role1.role_uuid }}" + register: role1_info + + - name: Print the role details + debug: + msg: "{{role1_info}}" + + - name: Delete the role. + ntnx_roles: + state: absent + role_uuid: "{{ updated_role1.role_uuid }}" + wait: true + register: op \ No newline at end of file diff --git a/examples/subnet_info.yml b/examples/subnet_info.yml index e06652169..1367e6706 100644 --- a/examples/subnet_info.yml +++ b/examples/subnet_info.yml @@ -14,7 +14,8 @@ tasks: - name: List subnets using subnet_type filter criteria ntnx_subnets_info: - filter: "subnet_type==VLAN" + filter: + subnet_type: "VLAN" kind: subnet register: result ignore_errors: True diff --git a/examples/user-groups.yml b/examples/user-groups.yml new file mode 100644 index 000000000..bd45a62a9 --- /dev/null +++ b/examples/user-groups.yml @@ -0,0 +1,50 @@ +--- +- name: user_group playbook + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + tasks: + - name: Setting Variables + set_fact: + distinguished_name: "" + principal_name: "" + directory_service_uuid: "" + identity_provider_uuid: "" + project: + uuid: "" + + - name: create user group + ntnx_user_groups: + distinguished_name: "{{distinguished_name}}" + project: + uuid: "{{project.uuid}}" + categories: + Environment: + - "Dev" + register: result + + - name: delete user group + ntnx_user_groups: + state: absent + user_group_uuid: "{{result.user_group_uuid}}" + register: result + + - name: create user group with idp + ntnx_user_groups: + idp: + idp_uuid: "{{identity_provider_uuid}}" + group_name: test_group_987 + register: result + + - name: delete user group + ntnx_user_groups: + state: absent + user_group_uuid: "{{result.user_group_uuid}}" + register: result diff --git a/examples/user.yml b/examples/user.yml new file mode 100644 index 000000000..050d0e381 --- /dev/null +++ b/examples/user.yml @@ -0,0 +1,61 @@ +--- +- name: users playbook + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + tasks: + - name: Setting Variables + set_fact: + directory_service_uuid: "" + principal_name: "" + project: + uuid: "" + identity_provider_uuid: "" + + - name: create local user + ntnx_users: + principal_name: "{{principal_name}}" + directory_service_uuid: "{{directory_service_uuid}}" + register: result + + - name: Delete created user + ntnx_users: + state: absent + user_uuid: "{{ result.user_uuid }}" + + - name: create local user with project and categories + ntnx_users: + principal_name: "{{principal_name}}" + directory_service_uuid: "{{directory_service_uuid}}" + project: + uuid: "{{project.uuid}}" + categories: + Environment: + - "Dev" + AppType: + - "Default" + register: result + + - name: Delete created user + ntnx_users: + state: absent + user_uuid: "{{ result.user_uuid }}" + + - name: create idp user + ntnx_users: + identity_provider_uuid: "{{identity_provider_uuid}}" + username: testing_user + register: result + ignore_errors: true + + - name: Delete created user + ntnx_users: + state: absent + user_uuid: "{{ result.user_uuid }}" diff --git a/examples/vm_info.yml b/examples/vm_info.yml index 95b8f98c1..ea234370a 100644 --- a/examples/vm_info.yml +++ b/examples/vm_info.yml @@ -17,7 +17,8 @@ - name: List vms using name filter criteria ntnx_vms_info: - filter: "vm_name=={{ vm_name }}" + filter: + vm_name: "{{ vm_name }}" kind: vm register: result ignore_errors: True diff --git a/examples/vpc_info.yml b/examples/vpc_info.yml index fcd498bf5..0ac7553bb 100644 --- a/examples/vpc_info.yml +++ b/examples/vpc_info.yml @@ -17,7 +17,8 @@ - name: List VPC using name filter criteria ntnx_vpcs_info: - filter: "name=={{ vpc_name }}" + filter: + name: "{{ vpc_name }}" kind: vpc register: result ignore_errors: True diff --git a/galaxy.yml b/galaxy.yml index 816b8afbc..eb125ce5e 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,6 +1,6 @@ namespace: "nutanix" name: "ncp" -version: "1.3.0" +version: "1.4.0" readme: "README.md" authors: - "Abhishek Chaudhary (@abhimutant)" diff --git a/meta/runtime.yml b/meta/runtime.yml index ac591d208..6c0b1753f 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -2,24 +2,43 @@ requires_ansible: '>=2.11.6' action_groups: ntnx: + - ntnx_acps + - ntnx_address_groups + - ntnx_categories - ntnx_floating_ips + - ntnx_hosts_info - ntnx_images - ntnx_image_placement_policy - ntnx_pbrs + - ntnx_roles + - ntnx_projects - ntnx_security_rules + - ntnx_service_groups - ntnx_static_routes - ntnx_subnets + - ntnx_users + - ntnx_user_groups - ntnx_vms_ova - ntnx_vms_clone - ntnx_vms - ntnx_vpcs + - ntnx_acps_info + - ntnx_address_groups_info + - ntnx_categories_info + - ntnx_clusters_info - ntnx_floating_ips_info - ntnx_images_info - ntnx_image_placement_policies_info - ntnx_pbrs_info + - ntnx_permissions_info + - ntnx_projects_info + - ntnx_roles_info - ntnx_security_rules_info + - ntnx_service_groups_info - ntnx_static_routes_info - ntnx_subnets_info + - ntnx_user_groups_info + - ntnx_users_info - ntnx_vms_info - ntnx_vpcs_info - ntnx_foundation_aos_packages_info @@ -34,3 +53,6 @@ action_groups: - ntnx_foundation_central_imaged_clusters_info - ntnx_foundation_central_api_keys - ntnx_foundation_central_api_keys_info + + + diff --git a/plugins/module_utils/entity.py b/plugins/module_utils/entity.py index 45006484e..35d789c8a 100644 --- a/plugins/module_utils/entity.py +++ b/plugins/module_utils/entity.py @@ -47,6 +47,7 @@ def create( data=None, endpoint=None, query=None, + method="POST", raise_error=True, no_response=False, timeout=30, @@ -56,7 +57,7 @@ def create( url = self._build_url_with_query(url, query) return self._fetch_url( url, - method="POST", + method=method, data=data, raise_error=raise_error, no_response=no_response, @@ -221,9 +222,22 @@ def get_spec(self, old_spec=None): return None, error return spec, None - def get_uuid(self, value, key="name", raise_error=True, no_response=False): - data = {"filter": "{0}=={1}".format(key, value), "length": 1} - resp = self.list(data, raise_error=raise_error, no_response=no_response) + def get_uuid( + self, + value, + key="name", + data=None, + entity_type=None, + raise_error=True, + no_response=False, + ): + filter_spec = ( + data if data else {"filter": "{0}=={1}".format(key, value), "length": 1} + ) + + resp = self.list( + data=filter_spec, raise_error=raise_error, no_response=no_response + ) entities = resp.get("entities") if resp else None if entities: for entity in entities: diff --git a/plugins/module_utils/prism/acps.py b/plugins/module_utils/prism/acps.py new file mode 100644 index 000000000..0dd7fea82 --- /dev/null +++ b/plugins/module_utils/prism/acps.py @@ -0,0 +1,104 @@ +# This file is part of Ansible +# 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 + +from copy import deepcopy + +from .prism import Prism +from .roles import get_role_uuid + + +class ACP(Prism): + def __init__(self, module): + resource_type = "/access_control_policies" + super(ACP, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = { + "name": self._build_spec_name, + "desc": self._build_spec_desc, + "role": self._build_spec_role, + "user_uuids": self._build_spec_user, + "user_group_uuids": self._build_spec_user_group, + "filters": self._build_spec_filters, + } + + def _get_default_spec(self): + return deepcopy( + { + "api_version": "3.1.0", + "metadata": {"kind": "access_control_policy"}, + "spec": {"name": None, "resources": {}}, + } + ) + + def _build_spec_name(self, payload, name): + payload["spec"]["name"] = name + return payload, None + + def _build_spec_desc(self, payload, desc): + payload["spec"]["description"] = desc + return payload, None + + def _build_spec_role(self, payload, config): + uuid, error = get_role_uuid(config, self.module) + if error: + return None, error + payload["spec"]["resources"]["role_reference"] = {"kind": "role", "uuid": uuid} + return payload, None + + def _build_spec_user(self, payload, config): + user_reference_list = [] + for item in config: + user_reference_list.append({"kind": "user", "uuid": item}) + payload["spec"]["resources"]["user_reference_list"] = user_reference_list + return payload, None + + def _build_spec_user_group(self, payload, config): + user_group_reference_list = [] + for item in config: + user_group_reference_list.append({"kind": "user_group", "uuid": item}) + payload["spec"]["resources"][ + "user_group_reference_list" + ] = user_group_reference_list + return payload, None + + def _build_spec_filters(self, payload, config): + filter_list = [] + for filter in config: + filter_spec = {} + if filter.get("scope_filter"): + scope_filters = [] + for item in filter["scope_filter"]: + scope_filter = {} + if item.get("lhs"): + scope_filter["left_hand_side"] = item["lhs"] + if item.get("operator"): + scope_filter["operator"] = item["operator"] + if item.get("rhs"): + scope_filter["right_hand_side"] = item["rhs"] + + if scope_filter: + scope_filters.append(scope_filter) + if scope_filters: + filter_spec["scope_filter_expression_list"] = scope_filters + + if filter.get("entity_filter"): + entity_filters = [] + for item in filter["entity_filter"]: + entity_filter = {} + if item.get("lhs"): + entity_filter["left_hand_side"] = {"entity_type": item["lhs"]} + if item.get("operator"): + entity_filter["operator"] = item["operator"] + if item.get("rhs"): + entity_filter["right_hand_side"] = item["rhs"] + + if entity_filter: + entity_filters.append(entity_filter) + if entity_filters: + filter_spec["entity_filter_expression_list"] = entity_filters + if filter_spec: + filter_list.append(filter_spec) + payload["spec"]["resources"]["filter_list"] = {"context_list": filter_list} + return payload, None diff --git a/plugins/module_utils/prism/address_groups.py b/plugins/module_utils/prism/address_groups.py index cbcff71cf..2933873ec 100644 --- a/plugins/module_utils/prism/address_groups.py +++ b/plugins/module_utils/prism/address_groups.py @@ -2,15 +2,22 @@ # 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 +from copy import deepcopy from .prism import Prism +__metaclass__ = type + class AddressGroup(Prism): def __init__(self, module): resource_type = "/address_groups" super(AddressGroup, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = { + "name": self._build_spec_name, + "desc": self._build_spec_desc, + "subnets": self._build_spec_subnets, + } def get_uuid(self, value, key="name", raise_error=True, no_response=False): data = {"filter": "{0}=={1}".format(key, value), "length": 1} @@ -22,6 +29,32 @@ def get_uuid(self, value, key="name", raise_error=True, no_response=False): return entity["uuid"] return None + def _get_default_spec(self): + return deepcopy({"name": None, "ip_address_block_list": []}) + + def _build_spec_name(self, payload, name): + payload["name"] = name + return payload, None + + def _build_spec_desc(self, payload, desc): + payload["description"] = desc + return payload, None + + def _build_spec_subnets(self, payload, subnets): + ip_address_block_list = [] + for subnet in subnets: + ip_address_block_list.append( + self._get_ip_address_block( + subnet["network_ip"], subnet["network_prefix"] + ) + ) + payload["ip_address_block_list"] = ip_address_block_list + return payload, None + + def _get_ip_address_block(self, ip, prefix): + spec = {"ip": ip, "prefix_length": prefix} + return spec + # Helper functions diff --git a/plugins/module_utils/prism/categories.py b/plugins/module_utils/prism/categories.py new file mode 100644 index 000000000..c4d409488 --- /dev/null +++ b/plugins/module_utils/prism/categories.py @@ -0,0 +1,86 @@ +# This file is part of Ansible +# 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 + +from copy import deepcopy + +from .prism import Prism + +__metaclass__ = type + + +class Category(Prism): + def __init__(self, module): + + resource_type = "/categories" + super(Category, self).__init__(module, resource_type=resource_type) + + +class CategoryKey(Category): + def __init__(self, module): + super(CategoryKey, self).__init__(module) + self.build_spec_methods = { + "name": self._build_spec_name, + "desc": self._build_spec_desc, + } + + def list(self, name): + data = {"kind": "category"} + endpoint = "{0}/list".format(name) + return super().list(data=data, use_base_url=True, endpoint=endpoint) + + def create(self, name, data): + return super().create(data=data, endpoint=name, method="PUT") + + def get_spec(self, old_spec=None): + if old_spec: + spec = self._strip_extra_attributes_from_old_spec(old_spec) + return super().get_spec(old_spec=spec) + return super().get_spec() + + def _get_default_spec(self): + return deepcopy( + { + "api_version": "3.1.0", + "name": None, + } + ) + + def _strip_extra_attributes_from_old_spec(self, old_spec): + spec = {} + default_spec = {"api_version": "3.1.0", "name": None, "description": None} + for k in default_spec: + v = old_spec.get(k) + if v: + spec[k] = v + + return spec + + def _build_spec_name(self, payload, name): + payload["name"] = name + return payload, None + + def _build_spec_desc(self, payload, desc): + payload["description"] = desc + return payload, None + + +class CategoryValue(Category): + def __init__(self, module): + super(CategoryValue, self).__init__(module) + + def create(self, name, data): + endpoint = "{0}/{1}".format(name, data["value"]) + return super().create(data=data, endpoint=endpoint, method="PUT") + + def delete(self, name, value): + endpoint = "{0}/{1}".format(name, value) + return super().delete(endpoint=endpoint, no_response=True) + + def _get_default_spec(self): + return deepcopy({"api_version": "3.1.0", "value": None}) + + def get_value_spec(self, value): + spec = self._get_default_spec() + spec["value"] = value + return spec diff --git a/plugins/module_utils/prism/clusters.py b/plugins/module_utils/prism/clusters.py index 3521f71e3..2f1fb9b50 100644 --- a/plugins/module_utils/prism/clusters.py +++ b/plugins/module_utils/prism/clusters.py @@ -8,10 +8,17 @@ class Cluster(Prism): + kind = "cluster" + def __init__(self, module): resource_type = "/clusters" super(Cluster, self).__init__(module, resource_type=resource_type) + @classmethod + def build_cluster_reference_spec(cls, uuid): + spec = {"kind": cls.kind, "uuid": uuid} + return spec + # Helper functions diff --git a/plugins/module_utils/prism/groups.py b/plugins/module_utils/prism/groups.py index dfcb1ab53..b259b7f68 100644 --- a/plugins/module_utils/prism/groups.py +++ b/plugins/module_utils/prism/groups.py @@ -13,7 +13,13 @@ def __init__(self, module): super(Groups, self).__init__(module, resource_type=resource_type) def get_uuid( - self, value, key="name", entity_type="", raise_error=True, no_response=False + self, + value, + key="name", + data=None, + entity_type="", + raise_error=True, + no_response=False, ): data = { "entity_type": entity_type, diff --git a/plugins/module_utils/prism/hosts.py b/plugins/module_utils/prism/hosts.py new file mode 100644 index 000000000..ada265ea4 --- /dev/null +++ b/plugins/module_utils/prism/hosts.py @@ -0,0 +1,13 @@ +# This file is part of Ansible +# 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 + +from .prism import Prism + + +class Host(Prism): + def __init__(self, module): + resource_type = "/hosts" + super(Host, self).__init__(module, resource_type=resource_type) diff --git a/plugins/module_utils/prism/permissions.py b/plugins/module_utils/prism/permissions.py new file mode 100644 index 000000000..32e8326ce --- /dev/null +++ b/plugins/module_utils/prism/permissions.py @@ -0,0 +1,62 @@ +# This file is part of Ansible +# 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 + +from .prism import Prism + + +class Permission(Prism): + kind = "permission" + + def __init__(self, module): + resource_type = "/permissions" + super(Permission, self).__init__(module, resource_type=resource_type) + + def get_uuid(self, value, key="name", raise_error=True, no_response=False): + filter_spec = { + "filter": "{0}=={1}".format(key, value), + "length": self.entities_limitation, + "offset": 0, + "kind": self.kind, + } + resp = self.list( + data=filter_spec, raise_error=raise_error, no_response=no_response + ) + for entity in resp["entities"]: + if entity["spec"]["name"] == value: + return entity["metadata"]["uuid"] + + # Incase there are more entities to check + while resp["total_matches"] > resp["length"] + resp["offset"]: + filter_spec["length"] = self.entities_limitation + filter_spec["offset"] = filter_spec["offset"] + self.entities_limitation + resp = self.list( + data=filter_spec, raise_error=raise_error, no_response=no_response + ) + for entity in resp["entities"]: + if entity["spec"]["name"] == value: + return entity["metadata"]["uuid"] + return None + + @classmethod + def build_permission_reference_spec(cls, uuid=None): + spec = {"kind": cls.kind, "uuid": uuid} + return spec + + +def get_permission_uuid(config, module): + if "name" in config: + users = Permission(module) + name = config["name"] + uuid = users.get_uuid(name) + if not uuid: + + error = "Permission {0} not found.".format(name) + return None, error + + elif "uuid" in config: + uuid = config["uuid"] + + return uuid, None diff --git a/plugins/module_utils/prism/projects.py b/plugins/module_utils/prism/projects.py index eec9f92bc..77389916a 100644 --- a/plugins/module_utils/prism/projects.py +++ b/plugins/module_utils/prism/projects.py @@ -2,12 +2,111 @@ # 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 +from copy import deepcopy + __metaclass__ = type +from .clusters import Cluster from .prism import Prism +from .subnets import Subnet, get_subnet_uuid class Project(Prism): def __init__(self, module): resource_type = "/projects" super(Project, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = { + "name": self._build_spec_name, + "desc": self._build_spec_desc, + "resource_limits": self._build_spec_resource_limits, + "clusters": self._build_spec_cluster_reference_list, + "default_subnet": self._build_spec_default_subnet, + "subnets": self._build_spec_subnets, + "users": self._build_spec_user_reference_list, + "external_user_groups": self._build_spec_external_user_group_reference_list, + } + + def _get_default_spec(self): + return deepcopy( + { + "api_version": "3.1.0", + "metadata": {"kind": "project"}, + "spec": { + "name": None, + "resources": {}, + }, + } + ) + + def _build_spec_name(self, payload, name): + payload["spec"]["name"] = name + return payload, None + + def _build_spec_desc(self, payload, desc): + payload["spec"]["description"] = desc + return payload, None + + def _build_spec_resource_limits(self, payload, resource_limits): + payload["spec"]["resources"]["resource_domain"] = {} + payload["spec"]["resources"]["resource_domain"]["resources"] = resource_limits + return payload, None + + def _build_spec_cluster_reference_list(self, payload, cluster_ref_list): + cluster_reference_specs = [] + for uuid in cluster_ref_list: + cluster_reference_specs.append(Cluster.build_cluster_reference_spec(uuid)) + payload["spec"]["resources"]["cluster_reference_list"] = cluster_reference_specs + return payload, None + + def _build_spec_default_subnet(self, payload, subnet_ref): + uuid, err = get_subnet_uuid(subnet_ref, self.module) + if err: + return None, err + + payload["spec"]["resources"][ + "default_subnet_reference" + ] = Subnet.build_subnet_reference_spec(uuid) + return payload, None + + def _build_spec_subnets(self, payload, subnet_ref_list): + subnet_reference_specs = [] + for ref in subnet_ref_list: + uuid, err = get_subnet_uuid(ref, self.module) + if err: + return None, err + subnet_reference_specs.append(Subnet.build_subnet_reference_spec(uuid)) + payload["spec"]["resources"]["subnet_reference_list"] = subnet_reference_specs + return payload, None + + def _build_spec_user_reference_list(self, payload, users): + user_reference_specs = [] + for uuid in users: + user_ref = {"kind": "user", "uuid": uuid} + user_reference_specs.append(user_ref) + payload["spec"]["resources"]["user_reference_list"] = user_reference_specs + return payload, None + + def _build_spec_external_user_group_reference_list(self, payload, ext_users): + user_groups_reference_specs = [] + for uuid in ext_users: + user_group_ref = {"kind": "user_group", "uuid": uuid} + user_groups_reference_specs.append(user_group_ref) + payload["spec"]["resources"][ + "external_user_group_reference_list" + ] = user_groups_reference_specs + return payload, None + + +def get_project_uuid(module, config): + if "name" in config: + project = Project(module) + name = config["name"] + uuid = project.get_uuid(name) + if not uuid: + error = "Project {0} not found.".format(name) + return None, error + + elif "uuid" in config: + uuid = config["uuid"] + + return uuid, None diff --git a/plugins/module_utils/prism/roles.py b/plugins/module_utils/prism/roles.py new file mode 100644 index 000000000..760d72a22 --- /dev/null +++ b/plugins/module_utils/prism/roles.py @@ -0,0 +1,65 @@ +# This file is part of Ansible +# 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 + +from copy import deepcopy + +from .permissions import Permission, get_permission_uuid +from .prism import Prism + +__metaclass__ = type + + +class Role(Prism): + def __init__(self, module): + resource_type = "/roles" + super(Role, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = { + "name": self._build_spec_name, + "desc": self._build_spec_desc, + "permissions": self._build_spec_permissions, + } + + def _get_default_spec(self): + return deepcopy( + { + "metadata": {"kind": "role"}, + "spec": {"resources": {"permission_reference_list": []}, "name": None}, + } + ) + + def _build_spec_name(self, payload, name): + payload["spec"]["name"] = name + return payload, None + + def _build_spec_desc(self, payload, desc): + payload["spec"]["description"] = desc + return payload, None + + def _build_spec_permissions(self, payload, permissions): + permission_ref_specs = [] + for permission in permissions: + uuid, err = get_permission_uuid(permission, self.module) + if err: + return None, err + permission_ref_specs.append( + Permission.build_permission_reference_spec(uuid) + ) + payload["spec"]["resources"]["permission_reference_list"] = permission_ref_specs + return payload, None + + +def get_role_uuid(config, module): + if "name" in config: + roles = Role(module) + name = config["name"] + uuid = roles.get_uuid(name) + if not uuid: + + error = "Role {0} not found.".format(name) + return None, error + + elif "uuid" in config: + uuid = config["uuid"] + + return uuid, None diff --git a/plugins/module_utils/prism/service_groups.py b/plugins/module_utils/prism/service_groups.py index 99f39cacd..d94ac61c8 100644 --- a/plugins/module_utils/prism/service_groups.py +++ b/plugins/module_utils/prism/service_groups.py @@ -4,6 +4,8 @@ __metaclass__ = type +from copy import deepcopy + from .prism import Prism @@ -11,9 +13,14 @@ class ServiceGroup(Prism): def __init__(self, module): resource_type = "/service_groups" super(ServiceGroup, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = { + "name": self._build_spec_name, + "desc": self._build_spec_desc, + "service_details": self._build_spec_service_details, + } def get_uuid(self, value, key="name", raise_error=True, no_response=False): - data = {"filter": "{0}=={1}".format(key, value), "length": 1} + data = {"filter": "{0}=={1}".format(key, value)} resp = self.list(data, raise_error=raise_error, no_response=no_response) entities = resp.get("entities") if resp else None if entities: @@ -22,6 +29,67 @@ def get_uuid(self, value, key="name", raise_error=True, no_response=False): return entity["uuid"] return None + def _get_default_spec(self): + return deepcopy( + { + "name": None, + "service_list": [], + } + ) + + def _build_spec_name(self, payload, value): + payload["name"] = value + return payload, None + + def _build_spec_desc(self, payload, value): + payload["description"] = value + return payload, None + + def _build_spec_service_details(self, payload, config): + service_list = [] + + if config.get("tcp"): + service = {} + service["protocol"] = "TCP" + port_range_list = self.generate_port_range_list(config["tcp"]) + service["tcp_port_range_list"] = port_range_list + service_list.append(service) + + if config.get("udp"): + service = {} + service["protocol"] = "UDP" + port_range_list = self.generate_port_range_list(config["udp"]) + service["udp_port_range_list"] = port_range_list + service_list.append(service) + + if config.get("icmp"): + service = {} + service["protocol"] = "ICMP" + service["icmp_type_code_list"] = config["icmp"] + service_list.append(service) + elif config.get("any_icmp"): + service = {} + service["protocol"] = "ICMP" + service["icmp_type_code_list"] = [] + service_list.append(service) + + payload["service_list"] = service_list + + return payload, None + + @staticmethod + def generate_port_range_list(config): + port_range_list = [] + if "*" not in config: + for port in config: + port = port.split("-") + port_range_list.append( + {"start_port": int(port[0]), "end_port": int(port[-1])} + ) + else: + port_range_list.append({"start_port": 0, "end_port": 65535}) + return port_range_list + # Helper functions diff --git a/plugins/module_utils/prism/static_routes.py b/plugins/module_utils/prism/static_routes.py index 9c2369c1e..5627e943b 100644 --- a/plugins/module_utils/prism/static_routes.py +++ b/plugins/module_utils/prism/static_routes.py @@ -11,12 +11,12 @@ from .vpn_connections import get_vpn_connection_uuid -class StaticRoutes(Vpc): +class StaticRoute(Vpc): default_route_dest = "0.0.0.0/0" route_tables_endpoint = "route_tables" def __init__(self, module): - super(StaticRoutes, self).__init__(module) + super(StaticRoute, self).__init__(module) self.build_spec_methods = { "static_routes": self._build_spec_static_routes, "remove_all_routes": self._build_spec_remove_all_routes, diff --git a/plugins/module_utils/prism/subnets.py b/plugins/module_utils/prism/subnets.py index 477a0ea73..3d8766cdf 100644 --- a/plugins/module_utils/prism/subnets.py +++ b/plugins/module_utils/prism/subnets.py @@ -13,6 +13,8 @@ class Subnet(Prism): + kind = "subnet" + def __init__(self, module): resource_type = "/subnets" super(Subnet, self).__init__(module, resource_type=resource_type) @@ -139,6 +141,11 @@ def _get_default_dhcp_spec(self): } ) + @classmethod + def build_subnet_reference_spec(cls, uuid): + spec = {"kind": cls.kind, "uuid": uuid} + return spec + # Helper functions diff --git a/plugins/module_utils/prism/user_groups.py b/plugins/module_utils/prism/user_groups.py new file mode 100644 index 000000000..1eb921b1c --- /dev/null +++ b/plugins/module_utils/prism/user_groups.py @@ -0,0 +1,62 @@ +# This file is part of Ansible +# 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 + +from copy import deepcopy + +from .prism import Prism +from .projects import get_project_uuid +from .spec.categories_mapping import CategoriesMapping + + +class UserGroup(Prism): + kind = "user_group" + + def __init__(self, module): + resource_type = "/user_groups" + super(UserGroup, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = { + "project": self._build_spec_project, + "distinguished_name": self._build_spec_user_distinguished_name, + "idp": self._build_spec_saml_user_group, + "categories": CategoriesMapping.build_categories_mapping_spec, + "remove_categories": CategoriesMapping.build_remove_all_categories_spec, + } + + def _get_default_spec(self): + return deepcopy( + { + "metadata": {"kind": "user_group"}, + "spec": {"resources": {}}, + } + ) + + def _build_spec_project(self, payload, config): + uuid, err = get_project_uuid(self.module, config) + if err: + return uuid, err + payload["metadata"].update( + {"project_reference": {"uuid": uuid, "kind": "project"}} + ) + return payload, None + + def _build_spec_user_distinguished_name(self, payload, config): + if "ou=" in config: + payload["spec"]["resources"]["directory_service_ou"] = { + "distinguished_name": config + } + else: + payload["spec"]["resources"]["directory_service_user_group"] = { + "distinguished_name": config + } + + return payload, None + + def _build_spec_saml_user_group(self, payload, config): + payload["spec"]["resources"]["saml_user_group"] = { + "name": config["group_name"], + "idpUuid": config["idp_uuid"], + } + return payload, None diff --git a/plugins/module_utils/prism/users.py b/plugins/module_utils/prism/users.py index f67f1f879..93eb35422 100644 --- a/plugins/module_utils/prism/users.py +++ b/plugins/module_utils/prism/users.py @@ -4,36 +4,86 @@ __metaclass__ = type +from copy import deepcopy + from .prism import Prism +from .projects import get_project_uuid +from .spec.categories_mapping import CategoriesMapping + +class User(Prism): + kind = "user" -class Users(Prism): def __init__(self, module): resource_type = "/users" - super(Users, self).__init__(module, resource_type=resource_type) + super(User, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = { + "project": self._build_spec_project, + "principal_name": self._build_spec_principal_name, + "directory_service_uuid": self._build_spec_directory_service, + "username": self._build_spec_username, + "identity_provider_uuid": self._build_spec_identity_provider, + "categories": CategoriesMapping.build_categories_mapping_spec, + "remove_categories": CategoriesMapping.build_remove_all_categories_spec, + } + + def _get_default_spec(self): + return deepcopy( + { + "metadata": {"kind": "user"}, + "spec": { + "resources": { + "directory_service_user": {}, + "identity_provider_user": {}, + } + }, + } + ) - def get_uuid(self, value, key="username", raise_error=True, no_response=False): - data = {"filter": "{0}=={1}".format(key, value), "length": 1} - resp = self.list(data, raise_error=raise_error, no_response=no_response) - entities = resp.get("entities") if resp else None - if entities: - for entity in entities: - if entity["status"]["name"] == value: - return entity["metadata"]["uuid"] - return None + def _build_spec_project(self, payload, config): + uuid, err = get_project_uuid(self.module, config) + if err: + return uuid, err + payload["metadata"].update( + {"project_reference": {"uuid": uuid, "kind": "project"}} + ) + return payload, None -def get_user_uuid(config, module): - if "name" in config: - users = Users(module) - name = config["name"] - uuid = users.get_uuid(name) - if not uuid: + def _build_spec_principal_name(self, payload, config): + payload["spec"]["resources"]["directory_service_user"].update( + { + "user_principal_name": config, + } + ) + return payload, None - error = "User {0} not found.".format(name) - return None, error + def _build_spec_directory_service(self, payload, config): + payload["spec"]["resources"]["directory_service_user"].update( + { + "directory_service_reference": { + "kind": "directory_service", + "uuid": config, + } + } + ) + payload["spec"]["resources"].pop("identity_provider_user") + return payload, None - elif "uuid" in config: - uuid = config["uuid"] + def _build_spec_username(self, payload, config): + payload["spec"]["resources"]["identity_provider_user"].update( + {"username": config} + ) + return payload, None - return uuid + def _build_spec_identity_provider(self, payload, config): + payload["spec"]["resources"]["identity_provider_user"].update( + { + "identity_provider_reference": { + "kind": "identity_provider", + "uuid": config, + } + } + ) + payload["spec"]["resources"].pop("directory_service_user") + return payload, None diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index 0d481bbb0..2af478d43 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -18,18 +18,18 @@ def remove_param_with_none_value(d): remove_param_with_none_value(e) -def strip_extra_attrs_from_status(status, spec): - for k, v in status.copy().items(): - if k not in spec: - status.pop(k) +def strip_extra_attrs(spec1, spec2): + for k, v in spec1.copy().items(): + if k not in spec2: + spec1.pop(k) elif isinstance(v, dict): - strip_extra_attrs_from_status(status[k], spec[k]) + strip_extra_attrs(spec1[k], spec2[k]) elif isinstance(v, list) and v and isinstance(v[0], dict): for i in range(len(v)): try: - strip_extra_attrs_from_status(status[k][i], spec[k][i]) + strip_extra_attrs(spec1[k][i], spec2[k][i]) except IndexError: - status[k] = spec[k] + spec1[k] = spec2[k] break diff --git a/plugins/modules/ntnx_acps.py b/plugins/modules/ntnx_acps.py new file mode 100644 index 000000000..50082428c --- /dev/null +++ b/plugins/modules/ntnx_acps.py @@ -0,0 +1,474 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_acps +short_description: acp module which suports acp Create, update and delete operations +version_added: 1.4.0 +description: 'Create, Update, Delete acp' +options: + name: + description: acp Name + required: False + type: str + acp_uuid: + description: acp UUID + type: str + desc: + description: The description of the association of a role to a user in a given context + required: False + type: str + user_uuids: + type: list + elements: str + description: The User(s) uuid being assigned a given role. + user_group_uuids: + type: list + elements: str + description: The User group(s) uuid being assigned a given role. + filters: + type: list + elements: dict + description: The list of filters, which define the entities. + suboptions: + scope_filter: + type: list + elements: dict + description: A list of Scope filter expressions. + suboptions: + lhs: + type: str + description: The left hand side of an expression. + choices: ["CATEGORY", "PROJECT", "CLUSTER", "VPC"] + operator: + type: str + description: The operator of the filter expression. + choices: ["IN", "IN_ALL", "NOT_IN"] + rhs: + type: dict + description: The right hand side of an expression. + suboptions: + collection: + type: str + description: A representative term for supported groupings of entities. ALL = All the entities of a given kind. + choices: ["ALL", "SELF_OWNED"] + categories: + type: dict + description: The category values represented as a dictionary of key -> list of values. e.g.{"env":["env1", "env2"]} + uuid_list: + type: list + elements: str + description: The explicit list of UUIDs for the given kind. + entity_filter: + type: list + elements: dict + description: A list of Entity filter expressions. + suboptions: + lhs: + type: str + description: The left hand side of an expression. + operator: + type: str + description: The operator of the filter expression. + choices: ["IN", "NOT_IN"] + rhs: + type: dict + description: The right hand side of an expression. + suboptions: + collection: + type: str + description: A representative term for supported groupings of entities. ALL = All the entities of a given kind. + choices: ["ALL", "SELF_OWNED"] + categories: + type: dict + description: The category values represented as a dictionary of key -> list of values. e.g.{"env":["env1", "env2"]} + uuid_list: + type: list + elements: str + description: The explicit list of UUIDs for the given kind. + role: + type: dict + description: The reference to a role + suboptions: + name: + description: the name of th role + required: False + type: str + uuid: + description: the uuid of the role + required: False + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_operations +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" + +EXAMPLES = r""" +- name: Create min ACP + ntnx_acps: + validate_certs: False + state: present + nutanix_host: "{{ IP }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + wait: true + name: MinACP + role: + uuid: '{{ role.uuid }}' + +- name: Create ACP with user reference + ntnx_acps: + validate_certs: False + state: present + nutanix_host: "{{ IP }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + name: acp_with_user_reference + role: + uuid: "{{ role.uuid }}" + user_uuids: + - "{{ user_uuid }}" + +- name: Create ACP with user ad user group reference + ntnx_acps: + validate_certs: False + state: present + nutanix_host: "{{ IP }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + name: acp_with_user_and_user_group_reference + role: + uuid: "{{ role.uuid }}" + user_uuids: + - "{{ user_uuid }}" + user_group_uuids: + - "{{ user_group_uuid }}" + +- name: Create ACP with all specfactions + ntnx_acps: + validate_certs: False + state: present + nutanix_host: "{{ IP }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + name: acp_with_all_specfactions + role: + uuid: "{{ role.uuid }}" + user_uuids: + - "{{ user_uuid }}" + user_group_uuids: + - "{{ user_group_uuid }}" + filters: + - scope_filter: + - + lhs: PROJECT + operator: IN + rhs: + uuid_list: + - "{{ project.uuid }}" + entity_filter: + - + lhs: ALL + operator: IN + rhs: + collection: ALL +""" + +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: '3.1' +metadata: + description: Metadata for ACP output + returned: always + type: dict + sample: + categories: {} + categories_mapping: {} + creation_time: '2022-06-15T11:59:38Z' + kind: access_control_policy + last_update_time: '2022-06-15T11:59:41Z' + owner_reference: + kind: user + name: admin + uuid: 00000000000-0000-0000-0000-00000000000 + spec_hash: '00000000000000000000000000000000000000000000000000' + spec_version: 0 + uuid: 00000000000-0000-0000-0000-00000000000 +spec: + description: An intentful representation of a subnet spec + returned: always + type: dict + sample: + description: desc, + name: name, + resources: + filter_list: + context_list: + entity_filter_expression_list: + left_hand_side: + entity_type: ALL + operator: IN, + right_hand_side: + collection: ALL + scope_filter_expression_list: + left_hand_side: PROJECT, + operator: IN, + right_hand_side: + uuid_list: + 00000000000-0000-0000-0000-00000000000 + role_reference: + kind: role, + uuid: 00000000000-0000-0000-0000-00000000000 + user_group_reference_list: + kind: user_group, + uuid: 00000000000-0000-0000-0000-00000000000 + user_reference_list: + kind: user, + uuid: 00000000000-0000-0000-0000-00000000000 +status: + description: An intentful representation of a ACP status + returned: always + type: dict + sample: { + "description": "desc", + "execution_context": { + "task_uuid": "00000000000-0000-0000-0000-00000000000" + }, + "is_system_defined": false, + "name": "name", + "resources": { + "filter_list": { + "context_list": { + "entity_filter_expression_list": { + "left_hand_side": { + "entity_type": "ALL" + }, + "operator": "IN", + "right_hand_side": { + "collection": "ALL" + } + }, + "scope_filter_expression_list": { + "left_hand_side": "PROJECT,", + "operator": "IN,", + "right_hand_side": { + "uuid_list": "00000000000-0000-0000-0000-00000000000" + } + } + } + }, + "role_reference": { + "kind": "role,", + "name": "rol1", + "uuid": "00000000000-0000-0000-0000-00000000000" + }, + "user_group_reference_list": { + "kind": "user_group,", + "name": "cn=ss,cn=users,dc=ss,dc=cc,dc=io,", + "uuid": "00000000000-0000-0000-0000-00000000000" + }, + "user_reference_list": { + "kind": "user,", + "name": "xx@xx.com", + "uuid": "00000000000-0000-0000-0000-00000000000" + } + }, + "state": "COMPLETE" + } +acp_uuid: + description: The created acp's uuid + returned: always + type: str + sample: 00000000000-0000-0000-0000-00000000000 +task_uuid: + description: The task uuid for the creation + returned: always + type: str + sample: 00000000000-0000-0000-0000-00000000000 +""" + +from ..module_utils import utils # noqa: E402 +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.acps import ACP # noqa: E402 +from ..module_utils.prism.tasks import Task # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + mutually_exclusive = [("name", "uuid")] + + entity_by_spec = dict(name=dict(type="str"), uuid=dict(type="str")) + + rhs_spec = dict( + collection=dict(type="str", choices=["ALL", "SELF_OWNED"]), + categories=dict(type="dict"), + uuid_list=dict(type="list", elements="str"), + ) + + scope_context_spec = dict( + lhs=dict(type="str", choices=["CATEGORY", "PROJECT", "CLUSTER", "VPC"]), + operator=dict(type="str", choices=["IN", "IN_ALL", "NOT_IN"]), + rhs=dict(type="dict", options=rhs_spec), + ) + + entity_context_spec = dict( + lhs=dict(type="str"), + operator=dict(type="str", choices=["IN", "NOT_IN"]), + rhs=dict(type="dict", options=rhs_spec), + ) + + filter_spec = dict( + scope_filter=dict(type="list", elements="dict", options=scope_context_spec), + entity_filter=dict(type="list", elements="dict", options=entity_context_spec), + ) + + module_args = dict( + name=dict(type="str"), + acp_uuid=dict(type="str"), + desc=dict(type="str"), + user_uuids=dict(type="list", elements="str"), + user_group_uuids=dict(type="list", elements="str"), + role=dict( + type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive + ), + filters=dict(type="list", elements="dict", options=filter_spec), + ) + + return module_args + + +# TO-DO: Test acps with VPC and CLUSTER scope +def create_acp(module, result): + acp = ACP(module) + spec, error = acp.get_spec() + if error: + result["error"] = error + module.fail_json(msg="Failed generating acp spec", **result) + + if module.check_mode: + result["response"] = spec + return + + resp = acp.create(spec) + acp_uuid = resp["metadata"]["uuid"] + result["changed"] = True + result["response"] = resp + result["acp_uuid"] = acp_uuid + result["task_uuid"] = resp["status"]["execution_context"]["task_uuid"] + + if module.params.get("wait"): + wait_for_task_completion(module, result) + resp = acp.read(acp_uuid) + result["response"] = resp + + +def update_acp(module, result): + acp_uuid = module.params["acp_uuid"] + state = module.params.get("state") + + acp = ACP(module) + resp = acp.read(acp_uuid) + result["response"] = resp + utils.strip_extra_attrs(resp["status"], resp["spec"]) + resp.pop("status") + + spec, error = acp.get_spec(resp) + + if error: + result["error"] = error + module.fail_json(msg="Failed generating ACP spec", **result) + + if module.check_mode: + result["response"] = spec + return + + if utils.check_for_idempotency(spec, resp, state=state): + result["skipped"] = True + module.exit_json(msg="Nothing to change") + + resp = acp.update(spec, acp_uuid) + acp_uuid = resp["metadata"]["uuid"] + result["changed"] = True + result["response"] = resp + result["acp_uuid"] = acp_uuid + result["task_uuid"] = resp["status"]["execution_context"]["task_uuid"] + + if module.params.get("wait"): + wait_for_task_completion(module, result) + resp = acp.read(acp_uuid) + result["response"] = resp + + +def delete_acp(module, result): + acp_uuid = module.params["acp_uuid"] + if not acp_uuid: + result["error"] = "Missing parameter acp_uuid in playbook" + module.fail_json(msg="Failed deleting acp", **result) + + acp = ACP(module) + resp = acp.delete(acp_uuid) + result["changed"] = True + result["response"] = resp + result["acp_uuid"] = acp_uuid + result["task_uuid"] = resp["status"]["execution_context"]["task_uuid"] + + if module.params.get("wait"): + wait_for_task_completion(module, result) + + +def wait_for_task_completion(module, result): + task = Task(module) + task_uuid = result["task_uuid"] + resp = task.wait_for_completion(task_uuid) + result["response"] = resp + + +def run_module(): + module = BaseModule( + argument_spec=get_module_spec(), + supports_check_mode=True, + required_if=[ + ("state", "present", ("name", "acp_uuid"), True), + ("state", "present", ("role", "acp_uuid"), True), + ("state", "absent", ("acp_uuid",)), + ], + ) + remove_param_with_none_value(module.params) + result = { + "changed": False, + "error": None, + "response": None, + "acp_uuid": None, + "task_uuid": None, + } + state = module.params["state"] + if state == "absent": + delete_acp(module, result) + elif module.params.get("acp_uuid"): + update_acp(module, result) + else: + create_acp(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_acps_info.py b/plugins/modules/ntnx_acps_info.py new file mode 100644 index 000000000..02362e3d3 --- /dev/null +++ b/plugins/modules/ntnx_acps_info.py @@ -0,0 +1,250 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_acps_info +short_description: acp info module +version_added: 1.4.0 +description: 'Get acp info' +options: + kind: + description: + - The kind name + type: str + default: access_control_policy + acp_uuid: + description: + - acp UUID + type: str + sort_order: + description: + - The sort order in which results are returned + type: str + choices: + - ASCENDING + - DESCENDING +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" +EXAMPLES = r""" + - name: List acp using name filter criteria + ntnx_acps_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + filter: + name: "{{ acp.name }}" + kind: access_control_policy + register: result + + - name: List acp using length, offset, sort order and name sort attribute + ntnx_acps_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + length: 1 + offset: 1 + sort_order: "ASCENDING" + sort_attribute: "name" + register: result +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: Metadata for acp_info list output + returned: always + type: dict + sample: { + "metadata": { + "kind": "access_control_policy", + "length": 1, + "offset": 2, + "sort_attribute": "name", + "sort_order": "DESCENDING", + "total_matches": 3 + } } +entities: + description: acp intent response + returned: always + type: list + sample: { + "entities": [ + { + "metadata": { + "categories": {}, + "categories_mapping": {}, + "creation_time": "", + "entity_version": "", + "kind": "access_control_policy", + "last_update_time": "", + "spec_hash": "", + "spec_version": 0, + "uuid": "" + }, + "spec": { + "description": "", + "name": "", + "resources": { + "filter_list": { + "context_list": [ + { + "entity_filter_expression_list": [ + { + "left_hand_side": { + "entity_type": "ALL" + }, + "operator": "IN", + "right_hand_side": { + "collection": "ALL" + } + } + ], + "scope_filter_expression_list": [ + { + "left_hand_side": "PROJECT", + "operator": "IN", + "right_hand_side": { + "uuid_list": [ + "" + ] + } + } + ] + } + ] + }, + "role_reference": { + "kind": "role", + "uuid": "" + }, + "user_group_reference_list": [], + "user_reference_list": [ + { + "kind": "user", + "name": "", + "uuid": "" + } + ] + } + }, + "status": { + "description": "", + "is_system_defined": false, + "name": "", + "resources": { + "filter_list": { + "context_list": [ + { + "entity_filter_expression_list": [ + { + "left_hand_side": { + "entity_type": "ALL" + }, + "operator": "IN", + "right_hand_side": { + "collection": "ALL" + } + } + ], + "scope_filter_expression_list": [ + { + "left_hand_side": "PROJECT", + "operator": "IN", + "right_hand_side": { + "uuid_list": [ + "" + ] + } + } + ] + } + ] + }, + "role_reference": { + "kind": "role", + "name": "test_role", + "uuid": "" + }, + "user_group_reference_list": [], + "user_reference_list": [] + }, + "state": "COMPLETE" + } + } + ] + } +""" + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.acps import ACP # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + acp_uuid=dict(type="str"), + kind=dict(type="str", default="access_control_policy"), + sort_order=dict(type="str", choices=["ASCENDING", "DESCENDING"]), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_acp(module, result): + acp = ACP(module) + acp_uuid = module.params.get("acp_uuid") + resp = acp.read(acp_uuid) + + result["response"] = resp + + +def get_acps(module, result): + acp = ACP(module) + spec, error = acp.get_info_spec() + + resp = acp.list(spec) + + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("acp_uuid"): + get_acp(module, result) + else: + get_acps(module, result) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_address_groups.py b/plugins/modules/ntnx_address_groups.py new file mode 100644 index 000000000..9b6d32880 --- /dev/null +++ b/plugins/modules/ntnx_address_groups.py @@ -0,0 +1,236 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_address_groups +short_description: module which supports address groups CRUD operations +version_added: 1.4.0 +description: "Create, Update, Delete Nutanix address groups" +options: + state: + description: + - when C(state)=present and address group uuid is not given then it will create new address group + - when C(state)=present and address group uuid given then it will update the address group + - when C(state)=absent, it will delete the address group + name: + description: + - name of the address group + - allowed to update + - required for creating address group + required: false + type: str + address_group_uuid: + description: + - uuid of the address group + - only required while updating or deleting + required: false + type: str + desc: + description: + - description of address group + - allowed to update + required: false + type: str + subnets: + description: + - list of details of subnets to be added in address group + - required while creating new address group + - allowed to update + - more than or equal to one subnets is always required, empty list is not considered + - during update, if used, it will override the subnets list of address group + required: false + type: list + elements: dict + suboptions: + network_prefix: + type: int + description: + - subnet prefix. + required: true + network_ip: + description: + - subnet ip. + type: str + required: true +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_operations +author: + - Prem Karat (@premkarat) + - Pradeepsingh Bhati (@bhati-pradeep) +""" + +EXAMPLES = r""" +- name: Create address group + ntnx_address_groups: + nutanix_host: + nutanix_username: + nutanix_password: + state: present + name: test-ansible-group-1 + desc: test-ansible-group-1-desc + subnets: + - network_ip: "10.1.1.0" + network_prefix: 24 + - network_ip: "10.1.2.2" + network_prefix: 32 + register: result + +- name: delete address group + ntnx_address_groups: + nutanix_host: + nutanix_username: + nutanix_password: + state: absent + address_group_uuid: "" + register: result +""" + +RETURN = r""" +response: + description: the response of address create using this module + returned: always + type: dict + sample: { + "address_group_string": "", + "description": "test_desc5", + "ip_address_block_list": [ + { + "ip": "10.1.1.0", + "prefix_length": 24 + } + ], + "name": "test_check2" + } +address_group_uuid: + description: The created address group uuid + returned: always + type: str + sample: "5d7bv3ab-d825-4cfd-879c-ec7a86a82cfd" +""" + +from ..module_utils import utils # noqa: E402 +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.address_groups import AddressGroup # noqa: E402 + + +def get_module_spec(): + subnet = dict( + network_prefix=dict(type="int", required=True), + network_ip=dict(type="str", required=True), + ) + + module_args = dict( + address_group_uuid=dict(type="str", required=False), + name=dict(type="str", required=False), + desc=dict(type="str", required=False), + subnets=dict(type="list", elements="dict", options=subnet, required=False), + ) + return module_args + + +def create_address_group(module, result): + _address_group = AddressGroup(module) + name = module.params["name"] + if _address_group.get_uuid(name): + module.fail_json(msg="Address group with given name already exists", **result) + + spec, err = _address_group.get_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating create Address group spec", **result) + + if module.check_mode: + result["response"] = spec + return + + resp = _address_group.create(data=spec) + + # read current state of address group + address_group = _address_group.read(uuid=resp["uuid"]) + result["response"] = address_group["address_group"] + result["changed"] = True + result["address_group_uuid"] = address_group["uuid"] + + +def update_address_group(module, result): + _address_group = AddressGroup(module) + uuid = module.params["address_group_uuid"] + result["address_group_uuid"] = uuid + + resp = _address_group.read(uuid=uuid) + address_group = resp["address_group"] + address_group.pop("address_group_string") + update_spec, err = _address_group.get_spec(address_group) + if err: + result["error"] = err + module.fail_json( + msg="Failed generating create Address group update spec", **result + ) + + # check for idempotency + if update_spec == address_group: + result["skipped"] = True + module.exit_json(msg="Nothing to change.") + + if module.check_mode: + result["response"] = update_spec + return + + _address_group.update(data=update_spec, uuid=uuid, no_response=True) + resp = _address_group.read(uuid=uuid) + result["response"] = resp["address_group"] + result["changed"] = True + + +def delete_address_group(module, result): + address_group = AddressGroup(module) + uuid = module.params["address_group_uuid"] + address_group.delete(uuid=uuid, no_response=True) + result["response"] = {"msg": "Address group deleted successfully"} + result["address_group_uuid"] = uuid + result["changed"] = True + + +def run_module(): + module = BaseModule( + argument_spec=get_module_spec(), + supports_check_mode=True, + required_if=[ + ("state", "present", ("name", "address_group_uuid"), True), + ("state", "present", ("subnets", "address_group_uuid"), True), + ("state", "absent", ("address_group_uuid",)), + ], + ) + utils.remove_param_with_none_value(module.params) + result = { + "changed": False, + "error": None, + "response": None, + "address_group_uuid": None, + } + state = module.params["state"] + if state == "present": + if module.params.get("address_group_uuid"): + update_address_group(module, result) + else: + create_address_group(module, result) + elif state == "absent": + delete_address_group(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_address_groups_info.py b/plugins/modules/ntnx_address_groups_info.py new file mode 100644 index 000000000..22728fffe --- /dev/null +++ b/plugins/modules/ntnx_address_groups_info.py @@ -0,0 +1,156 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_address_groups_info +short_description: address groups info module +version_added: 1.4.0 +description: 'Get address groups info' +options: + kind: + description: + - The kind name + type: str + default: address_group + address_group_uuid: + description: + - address group UUID + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Pradeepsingh Bhati (@bhati-pradeep) +""" +EXAMPLES = r""" +- name: List all address groups + ntnx_address_groups_info: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + register: result + +- name: List address groups using uuid criteria + ntnx_address_groups_info: + nutanix_host: + nutanix_username: + nutanix_password: + address_group_uuid: "" + register: result + +- name: List address groups using filter criteria + ntnx_address_groups_info: + nutanix_host: + nutanix_username: + nutanix_password: + filter: + name: "" + register: result +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: + - Metadata for address groups list output + - Below struct sample is was obtained when we used length=1 for listing address groups + returned: always + type: dict + sample: { + "kind": "address_group", + "total_matches": 2 + } +entities: + description: + - entities intent response + - Below struct sample is was obtained when we used length=1 for listing address groups + returned: always + type: list + sample: [ + { + "address_group": { + "address_group_string": "", + "description": "test_desc5", + "ip_address_block_list": [ + { + "ip": "10.1.1.3", + "prefix_length": 32 + } + ], + "name": "test_check2" + }, + "uuid": "c19c83f0-2ac9-4f5f-9c51-64484d08e5db" + } + ] + +""" + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.address_groups import AddressGroup # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + address_group_uuid=dict(type="str"), + kind=dict(type="str", default="address_group"), + sort_order=dict(type="str"), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_address_group(module, result): + address_group = AddressGroup(module) + address_group_uuid = module.params.get("address_group_uuid") + resp = address_group.read(address_group_uuid) + + result["response"] = resp["address_group"] + + +def get_address_groups(module, result): + address_group = AddressGroup(module) + spec, err = address_group.get_info_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating info spec for Address group", **result) + resp = address_group.list(spec) + + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("address_group_uuid"): + get_address_group(module, result) + else: + get_address_groups(module, result) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_categories.py b/plugins/modules/ntnx_categories.py new file mode 100644 index 000000000..a2855894e --- /dev/null +++ b/plugins/modules/ntnx_categories.py @@ -0,0 +1,318 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_categories +short_description: category module which supports pc category management CRUD operations +version_added: 1.4.0 +description: "Create, Update, Delete categories" +options: + remove_values: + description: + - it indicates to remove all values of the specfied category + - This attribute can be only used with C(state) is absent + - This attribute is mutually exclusive with C(values) when state is absent + type: bool + required: false + default: false + name: + description: + - Name of PC category + - Category will be deleted along with associated values when C(name) is given without C(values) if C(state) is present. + type: str + required: True + desc: + description: the description of PC category + type: str + required: false + values: + description: + - list of values of the category to be created for given C(name) when C(state) is present + - list of values of the category to be removed for given C(name) when C(state) is absent + - This attribute is mutually exclusive with C(remove_values) + type: list + required: false + elements: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_operations +author: + - Prem Karat (@premkarat) + - Pradeepsingh Bhati (@bhati-pradeep) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" + +EXAMPLES = r""" +- name: Create only category key with description + ntnx_categories: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + state: "present" + name: "{{first_category.name}}" + desc: "{{first_category.desc}}" + register: result +- name: Add values to existing category key having no values & Update description + ntnx_categories: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + state: "present" + name: "{{first_category.name}}" + desc: "{{first_category.update_desc}}" + values: + - "{{values.0}}" + - "{{values.1}}" + register: result +- name: update existing category by deleting some values + ntnx_categories: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + state: "absent" + name: "{{first_category.name}}" + desc: "{{first_category.update_desc}}" + values: + - "{{values.1}}" + register: result +- name: update existing category by deleting all values + ntnx_categories: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + state: "absent" + name: "{{first_category.name}}" + remove_values: true + register: result +- name: Delete the category + ntnx_categories: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + state: "absent" + name: "{{first_category.name}}" + register: result +- name: Create category key and value together + ntnx_categories: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + state: "present" + name: "{{second_category.name}}" + desc: test description + values: + - "{{values.0}}" + - "{{values.1}}" + register: result +""" + +RETURN = r""" +category_key: + description: category key name + returned: always + type: dict + sample: { + "capabilities": { + "cardinality": null + }, + "description": "test description", + "name": "test-cat1", + "system_defined": false + } +category_values: + description: list of all values of the category key + returned: always + type: list + sample: [ + { + "description": null, + "name": "test-cat1", + "system_defined": false, + "value": "value1" + }, + { + "description": null, + "name": "test-cat1", + "system_defined": false, + "value": "value2" + } + ] +""" + +from ..module_utils import utils # noqa: E402 +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.categories import CategoryKey, CategoryValue # noqa: E402 + + +def get_module_spec(): + module_args = dict( + name=dict(type="str", required=True), + desc=dict(type="str", required=False), + values=dict(type="list", elements="str", required=False), + remove_values=dict(type="bool", required=False, default=False), + ) + return module_args + + +def create_categories(module, result): + _category_key = CategoryKey(module) + name = module.params["name"] + + # check if new category create is required or not + category_key = _category_key.read(endpoint=name, raise_error=False) + category_key_values = {} + category_key_exists = False + if not category_key or category_key.get("state") == "ERROR": + category_key_spec, err = _category_key.get_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating create category key spec", **result) + else: + category_key_exists = True + category_key_spec, err = _category_key.get_spec(category_key) + if err: + result["error"] = err + module.fail_json(msg="Failed generating category key update spec", **result) + utils.strip_extra_attrs(category_key, category_key_spec) + resp = _category_key.list(name) + category_key_values = [] + for v in resp.get("entities", []): + category_key_values.append(v["value"]) + + # create spec for all the values which needed to be added to category key + values = module.params.get("values") + category_values_specs = [] + _category_value = CategoryValue(module) + if values: + for value in values: + if value not in category_key_values: + category_values_specs.append(_category_value.get_value_spec(value)) + + # indempotency check + if not category_values_specs and ( + category_key_exists and (category_key == category_key_spec) + ): + result["skipped"] = True + module.exit_json(msg="Nothing to update.") + + # check mode + if module.check_mode: + response = {"category_key": {}, "category_values": {}} + if category_key_exists and (category_key == category_key_spec): + response["category_key"] = {"msg": "Nothing to update."} + else: + response["category_key"] = category_key_spec + + if not category_values_specs: + response["category_values"] = {"msg": "Nothing to update."} + else: + response["category_values"] = category_values_specs + + result["response"] = response + return + + # create/update category + if not category_key_exists or (category_key != category_key_spec): + resp = _category_key.create(name, category_key_spec) + result["response"]["category_key"] = resp + result["changed"] = True + + # add category values + if category_values_specs: + responses = [] + for value_spec in category_values_specs: + resp = _category_value.create(name, value_spec) + responses.append(resp) + result["response"]["category_values"] = responses + + +def delete_category_values(module, name, values): + _category_value = CategoryValue(module) + for value in values: + _category_value.delete(name, value) + + +def delete_categories(module, result): + name = module.params["name"] + _category_key = CategoryKey(module) + if module.params.get("remove_values", False): + resp = _category_key.list(name) + category_key_values = [] + for v in resp.get("entities", []): + category_key_values.append(v["value"]) + delete_category_values(module, name, category_key_values) + result["response"] = { + "msg": "All values for category key: {0} has been deleted successfully.".format( + name + ) + } + + elif module.params.get("values"): + values = module.params["values"] + delete_category_values(module, name, values) + result["response"] = { + "msg": "Given values for category key: {0} has been deleted successfully.".format( + name + ) + } + + else: + # first delete all values if exists + resp = _category_key.list(name) + category_key_values = [] + for v in resp.get("entities", []): + category_key_values.append(v["value"]) + delete_category_values(module, name, category_key_values) + + # delete the category + resp = _category_key.delete(uuid=name, no_response=True) + result["response"] = { + "msg": "Category key: {0} has been deleted successfully along with all associated values.".format( + name + ) + } + + result["changed"] = True + + +def run_module(): + + module = BaseModule( + argument_spec=get_module_spec(), + supports_check_mode=True, + ) + utils.remove_param_with_none_value(module.params) + result = { + "response": {}, + "error": None, + "changed": False, + } + state = module.params["state"] + if state == "present": + create_categories(module, result) + else: + delete_categories(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_categories_info.py b/plugins/modules/ntnx_categories_info.py new file mode 100644 index 000000000..7cf558af7 --- /dev/null +++ b/plugins/modules/ntnx_categories_info.py @@ -0,0 +1,164 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_categories_info +short_description: categories info module +version_added: 1.4.0 +description: 'Get categories info' +options: + kind: + description: + - The kind name + type: str + default: category + name: + description: + - The category name + - Using this will also fetch all the category values associated with it + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Pradeepsingh Bhati (@bhati-pradeep) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" +EXAMPLES = r""" +- name: test getting all categories + ntnx_categories_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + register: result + ignore_errors: true + +- name: test getting the category with filter by it's name + ntnx_categories_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + filter: + name: "{{category_name}}" + register: result + +- name: test getting the category by it's name + ntnx_categories_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + name: "{{category_name}}" + register: result +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: Metadata for categories list output + returned: always + type: dict + sample: { + "filter": "", + "kind": "category_key", + "length": 2, + "offset": 0, + "total_matches": 2 + } +entities: + description: categories intent response + returned: always + type: list + sample: [ + { + "description": "Application type.", + "name": "AppType", + "system_defined": true + }, + { + "description": "Environment type.", + "name": "Environment", + "system_defined": true + } + ] + +""" + + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.categories import Category, CategoryKey # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + name=dict(type="str"), + kind=dict(type="str", default="category"), + sort_order=dict(type="str"), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_category(module, result): + key_obj = CategoryKey(module) + name = module.params.get("name") + category_key = key_obj.read(endpoint=name, raise_error=False) + if not category_key or category_key.get("state") == "ERROR": + result["response"] = {} + return + values = key_obj.list(name) + result["response"] = {"category_key": category_key, "category_values": values} + + +def get_categories(module, result): + categories = Category(module) + spec, err = categories.get_info_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating Categories info Spec", **result) + resp = categories.list(spec) + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + mutually_exclusive=[ + ("name", "filter"), + ], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("name"): + get_category(module, result) + else: + get_categories(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_clusters_info.py b/plugins/modules/ntnx_clusters_info.py new file mode 100644 index 000000000..33b100eb3 --- /dev/null +++ b/plugins/modules/ntnx_clusters_info.py @@ -0,0 +1,245 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_clusters_info +short_description: cluster info module +version_added: 1.4.0 +description: 'Get cluster info' +options: + kind: + description: + - The kind name + type: str + default: cluster + cluster_uuid: + description: + - cluster UUID + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" +EXAMPLES = r""" + - name: List clusterss + ntnx_clusters_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + kind: cluster + register: result + + - name: test getting particular cluster using uuid + ntnx_clusters_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + cluster_uuid: cluster_uuid + register: result +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: Metadata for clusters list output + returned: always + type: dict + sample: { + "metadata": { + "kind": "cluster", + "length": 6, + "offset": 0, + "sort_attribute": "priority", + "sort_order": "ASCENDING", + "total_matches": 6 + } + } +entities: + description: cluster intent response + returned: always + type: list + sample: { + "entities": [ { + "metadata": { + "categories": {}, + "categories_mapping": {}, + "creation_time": "", + "kind": "cluster", + "last_update_time": "", + "spec_hash": "", + "spec_version": "", + "uuid": "" + }, + "spec": { + "name": "Unnamed", + "resources": { + "config": { + "domain_awareness_level": "", + "enabled_feature_list": [ + "PASSWORD_REMOTE_LOGIN_ENABLED", + "SHADOW_CLONES_ENABLED" + ], + "encryption_status": "NOT_SUPPORTED", + "operation_mode": "NORMAL", + "redundancy_factor": 2, + "software_map": { + "NCC": { + "software_type": "NCC", + "status": "INSTALLED", + "version": "" + }, + "NOS": { + "software_type": "NOS", + "status": "INSTALLED", + "version": "" + } + }, + "supported_information_verbosity": "BASIC_PLUS_CORE_DUMP", + "timezone": "Atlantic/Reykjavik" + }, + "network": { + "external_ip": "", + "external_subnet": "", + "internal_subnet": "", + "name_server_ip_list": [ + "", + ], + "ntp_server_ip_list": [ + "", + ] + } + } + }, + "status": { + "name": "Unnamed", + "resources": { + "config": { + "build": { + "build_type": "release", + "commit_date": "", + "commit_id": "", + "full_version": "", + "short_commit_id": "", + "version": "" + }, + "cluster_arch": "", + "domain_awareness_level": "NODE", + "enabled_feature_list": [ + "PASSWORD_REMOTE_LOGIN_ENABLED", + "SHADOW_CLONES_ENABLED" + ], + "encryption_status": "NOT_SUPPORTED", + "is_available": true, + "operation_mode": "NORMAL", + "redundancy_factor": 2, + "service_list": [ + "PRISM_CENTRAL" + ], + "software_map": { + "NCC": { + "software_type": "NCC", + "status": "INSTALLED", + "version": "" + }, + "NOS": { + "software_type": "NOS", + "status": "INSTALLED", + "version": "" + } + }, + "supported_information_verbosity": "BASIC_PLUS_CORE_DUMP", + "timezone": "Atlantic/Reykjavik" + }, + "network": { + "external_ip": "", + "external_subnet": "", + "internal_subnet": "", + "name_server_ip_list": [ + "" + ], + "ntp_server_ip_list": [ + "", + ] + }, + "runtime_status_list": [ + "SSP_CONFIG_OWNER" + ] + }, + "state": "COMPLETE" + } + } + ], + } +""" + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.clusters import Cluster # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + cluster_uuid=dict(type="str"), + kind=dict(type="str", default="cluster"), + sort_order=dict(type="str"), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_cluster(module, result): + cluster = Cluster(module) + cluster_uuid = module.params.get("cluster_uuid") + resp = cluster.read(cluster_uuid) + + result["response"] = resp + + +def get_clusters(module, result): + cluster = Cluster(module) + spec, error = cluster.get_info_spec() + + resp = cluster.list(spec) + + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("cluster_uuid"): + get_cluster(module, result) + else: + get_clusters(module, result) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_floating_ips_info.py b/plugins/modules/ntnx_floating_ips_info.py index 4421db48d..bb0389e5f 100644 --- a/plugins/modules/ntnx_floating_ips_info.py +++ b/plugins/modules/ntnx_floating_ips_info.py @@ -30,20 +30,20 @@ - Prem Karat (@premkarat) - Gevorg Khachatryan (@Gevorg-Khachatryan-97) - Alaa Bishtawi (@alaa-bish) - - Dina AbuHijleh (@dina-abuhijleh) """ EXAMPLES = r""" - - name: List pbrs using ip starts with 10 filter criteria + - name: List Floating ip using ip starts with 10 filter criteria ntnx_floating_ips_info: nutanix_host: "{{ ip }}" nutanix_username: "{{ username }}" nutanix_password: "{{ password }}" validate_certs: False - filter: "floating_ip==10." + filter: + floating_ip: "10." kind: floating_ip register: result - - name: List pbrs using length, offset, sort order and floating_ip sort attribute + - name: List Floating ip using length, offset, sort order and floating_ip sort attribute ntnx_floating_ips_info: nutanix_host: "{{ ip }}" nutanix_username: "{{ username }}" diff --git a/plugins/modules/ntnx_hosts_info.py b/plugins/modules/ntnx_hosts_info.py new file mode 100644 index 000000000..8b7331677 --- /dev/null +++ b/plugins/modules/ntnx_hosts_info.py @@ -0,0 +1,206 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_hosts_info +short_description: host info module +version_added: 1.4.0 +description: 'Get host info' +options: + kind: + description: + - The kind name + type: str + default: host + host_uuid: + description: + - host UUID + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" +EXAMPLES = r""" + - name: List hosts + ntnx_hosts_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + kind: host + register: result + + - name: test getting particular host using uuid + ntnx_hosts_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + host_uuid: + register: result +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: Metadata for hosts list output + returned: always + type: dict + sample: { + "metadata": { + "kind": "host", + "length": 6, + "offset": 0, + "sort_attribute": "", + "sort_order": "", + "total_matches": 6 + } + } +entities: + description: host intent response + returned: always + type: list + sample: { + "entities": [ + { + "metadata": { + "categories": {}, + "categories_mapping": {}, + "creation_time": "", + "kind": "host", + "last_update_time": "", + "spec_hash": "", + "spec_version": 0, + "uuid": "" + }, + "spec": { + "resources": { + "controller_vm": { + "ip": "", + "oplog_usage": { + "oplog_disk_pct": "", + "oplog_disk_size": "" + } + } + } + }, + "status": { + "cluster_reference": { + "kind": "cluster", + "uuid": "" + }, + "resources": { + "block": { + "block_model": "null", + "block_serial_number": "null" + }, + "controller_vm": { + "ip": "", + "oplog_usage": { + "oplog_disk_pct": "", + "oplog_disk_size": "" + } + }, + "gpu_list": [], + "host_disks_reference_list": [ + { + "kind": "disk", + "uuid": "" + }, + { + "kind": "disk", + "uuid": "" + }, + { + "kind": "disk", + "uuid": "" + }, + { + "kind": "disk", + "uuid": "" + } + ], + "host_nics_id_list": [], + "host_type": "HYPER_CONVERGED", + "rackable_unit_reference": { + "kind": "rackable_unit", + "uuid": "" + }, + "serial_number": "" + }, + "state": "COMPLETE" + } + } + ], + } +""" + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.hosts import Host # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + host_uuid=dict(type="str"), + kind=dict(type="str", default="host"), + sort_order=dict(type="str"), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_host(module, result): + host = Host(module) + host_uuid = module.params.get("host_uuid") + resp = host.read(host_uuid) + + result["response"] = resp + + +def get_hosts(module, result): + host = Host(module) + spec, error = host.get_info_spec() + + resp = host.list(spec) + + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("host_uuid"): + get_host(module, result) + else: + get_hosts(module, result) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_image_placement_policy.py b/plugins/modules/ntnx_image_placement_policy.py index 9f87fb9ae..087e7ea56 100644 --- a/plugins/modules/ntnx_image_placement_policy.py +++ b/plugins/modules/ntnx_image_placement_policy.py @@ -335,7 +335,7 @@ def update_policy(module, result): # read the current state of policy resp = policy_obj.read(policy_uuid) - utils.strip_extra_attrs_from_status(resp["status"], resp["spec"]) + utils.strip_extra_attrs(resp["status"], resp["spec"]) resp["spec"] = resp.pop("status") # new spec for updating policy diff --git a/plugins/modules/ntnx_images.py b/plugins/modules/ntnx_images.py index fe22e6f40..8733b9df7 100644 --- a/plugins/modules/ntnx_images.py +++ b/plugins/modules/ntnx_images.py @@ -411,7 +411,7 @@ def update_image(module, result): # read the current state of image resp = image.read(image_uuid) - utils.strip_extra_attrs_from_status(resp["status"], resp["spec"]) + utils.strip_extra_attrs(resp["status"], resp["spec"]) resp["spec"] = resp.pop("status") # new spec for updating image diff --git a/plugins/modules/ntnx_pbrs_info.py b/plugins/modules/ntnx_pbrs_info.py index de5110380..082a46e70 100644 --- a/plugins/modules/ntnx_pbrs_info.py +++ b/plugins/modules/ntnx_pbrs_info.py @@ -39,7 +39,8 @@ nutanix_username: "{{ username }}" nutanix_password: "{{ password }}" validate_certs: False - filter: "priority==2" + filter: + priority: "2" kind: routing_policy register: result diff --git a/plugins/modules/ntnx_permissions_info.py b/plugins/modules/ntnx_permissions_info.py new file mode 100644 index 000000000..90c1f75bc --- /dev/null +++ b/plugins/modules/ntnx_permissions_info.py @@ -0,0 +1,185 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_permissions_info +short_description: permissions info module +version_added: 1.4.0 +description: 'Get permissions info' +options: + kind: + description: + - The kind name + type: str + default: permission + permission_uuid: + description: + - permission UUID + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Pradeepsingh Bhati (@bhati-pradeep) +""" +EXAMPLES = r""" +- name: List all permissions + ntnx_permissions_info: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + register: result + +- name: List permission using uuid criteria + ntnx_permissions_info: + permission_uuid: "{{ test_permission_uuid }}" + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + register: result + +- name: List permissions using filter criteria + ntnx_permissions_info: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + filter: + name: "{{ test_permission_name }}" + register: result +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: + - Metadata for permission list output + - Below struct is only obtained when we use filters or list permissions using length, etc. + returned: always + type: dict + sample: { + "kind": "permission", + "length": 20, + "offset": 0, + "total_matches": 1 + } +entities: + description: + - permission intent response + - Below struct is only obtained when we use filters or list permissions using length, etc. + returned: always + type: list + sample: [ + { + "metadata": { + "categories": {}, + "categories_mapping": {}, + "creation_time": "2022-07-05T18:28:26Z", + "kind": "permission", + "last_update_time": "2022-07-05T18:28:26Z", + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 0, + "uuid": "asdas3a77f4-73d4-4875-a8b9-3d2c068b8042" + }, + "spec": { + "description": "Allows to xyz", + "name": "permission_xyz", + "resources": { + "fields": { + "field_mode": "DISALLOWED", + "field_name_list": [] + }, + "kind": "", + "operation": "update" + } + }, + "status": { + "description": "Allows to xyz", + "name": "permission_xyz", + "resources": { + "fields": { + "field_mode": "DISALLOWED", + "field_name_list": [] + }, + "kind": "", + "operation": "update" + }, + "state": "COMPLETE" + } + } + ] +""" + + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.permissions import Permission # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + permission_uuid=dict(type="str"), + kind=dict(type="str", default="permission"), + sort_order=dict(type="str"), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_permission(module, result): + permissions = Permission(module) + uuid = module.params.get("permission_uuid") + resp = permissions.read(uuid) + result["response"] = resp + + +def get_permissions(module, result): + permissions = Permission(module) + spec, err = permissions.get_info_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating Permissions info Spec", **result) + resp = permissions.list(spec) + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + mutually_exclusive=[ + ("permission_uuid", "filter"), + ], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("permission_uuid"): + get_permission(module, result) + else: + get_permissions(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_projects.py b/plugins/modules/ntnx_projects.py new file mode 100644 index 000000000..1510e255b --- /dev/null +++ b/plugins/modules/ntnx_projects.py @@ -0,0 +1,394 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_projects +short_description: module for create, update and delete pc projects +version_added: 1.4.0 +description: "module for create, update and delete pc projects" +options: + wait: + description: Wait for the operations to complete. + type: bool + required: false + default: True + name: + description: + - project name + - cannot update once project is created + required: false + type: str + project_uuid: + description: + - This field can be used for update and delete of project + - if C(project_uuid) and C(state)==present will update the project + - if C(project_uuid) and C(state)==absent will delete the project + type: str + required: false + desc: + description: A description for project. + required: false + type: str + resource_limits: + description: resource limit quotas for project. + required: false + type: list + elements: dict + suboptions: + resource_type: + description: Type of resource limit + required: true + type: str + choices: + - VCPUS + - STORAGE + - MEMORY + limit: + description: + - limit value for given C(resource_type) + - for C(resource_type) as VCPUS, unit is counts + - for C(resource_type) as MEMORY or STORAGE, unit is bytes + required: true + type: int + default_subnet: + description: default subnet reference + type: dict + required: false + suboptions: + name: + description: + - subnet name + - Mutually exclusive with C(uuid) + type: str + uuid: + description: + - subnet UUID + - Mutually exclusive with C(name) + type: str + subnets: + description: list of subnets to be added in project + type: list + elements: dict + required: false + suboptions: + name: + description: + - subnet name + - Mutually exclusive with C(uuid) + type: str + uuid: + description: + - subnet UUID + - Mutually exclusive with C(name) + type: str + users: + description: + - list of uuid of users to be added in project + - this won't add role to the users, for same use ntnx_acps modules + required: false + type: list + elements: str + external_user_groups: + description: + - list of uuid of user groups to be added in project + - this won't add role to the users, for same use ntnx_acps modules + required: false + type: list + elements: str + clusters: + description: + - list of uuid of cluster to be added in project + - Adding clusters is supported for PC versions >= pc.2022.1 + required: false + type: list + elements: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_operations +author: + - Prem Karat (@premkarat) + - Pradeepsingh Bhati (@bhati-pradeep) +""" + +EXAMPLES = r""" +- name: Create Project with all specs + ntnx_projects: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + name: "test-ansible-project-1" + desc: desc-123 + subnets: + - name: "{{ network.dhcp.name }}" + - uuid: "{{ static.uuid }}" + default_subnet: + name: "{{ network.dhcp.name }}" + users: + - "{{ users[0] }}" + - "{{ users[1] }}" + external_user_groups: + - "{{ user_groups[0] }}" + resource_limits: + - resource_type: STORAGE + limit: 2046 + register: result + +- name: Delete created project + ntnx_projects: + state: absent + project_uuid: "" + wait: true + register: result +""" + +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: The project kind metadata + returned: always + type: dict + sample: { + "categories": {}, + "categories_mapping": {}, + "creation_time": "2022-07-18T06:44:52Z", + "kind": "project", + "last_update_time": "2022-07-18T06:44:54Z", + "owner_reference": { + "kind": "user", + "name": "admin", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "project_reference": { + "kind": "project", + "name": "test_project12-3523111", + "uuid": "df78c7800-4232-4ba8-a125-a2478f9383a9" + }, + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 0, + "uuid": "df78c7800-4232-4ba8-a125-a2478f9383a9" + } +spec: + description: An intentful representation of a project spec + returned: always + type: dict + sample: { + "description": "check123233221", + "name": "test_project12-3523111", + "resources": { + "resource_domain": { + "resources": [ + { + "limit": 10000000, + "resource_type": "STORAGE" + } + ] + } + } + } +status: + description: An intentful representation of a project status + returned: always + type: dict + sample: { + "description": "check123233221", + "execution_context": { + "task_uuid": [ + "6a094910-b033-4c9e-9cb7-757861934614" + ] + }, + "name": "test_project12-3523111", + "resources": { + "account_reference_list": [], + "cluster_reference_list": [], + "environment_reference_list": [], + "external_network_list": [], + "external_user_group_reference_list": [], + "is_default": false, + "resource_domain": { + "resources": [ + { + "limit": 10000000, + "resource_type": "STORAGE", + "units": "BYTES", + "value": 0 + } + ] + }, + "subnet_reference_list": [], + "tunnel_reference_list": [], + "user_reference_list": [], + "vpc_reference_list": [] + }, + "state": "COMPLETE" + } +project_uuid: + description: The created project's uuid + returned: always + type: str + sample: "df78c7800-4232-4ba8-a125-a2478f9383a9" +""" + +from ..module_utils import utils # noqa: E402 +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.projects import Project # noqa: E402 +from ..module_utils.prism.tasks import Task # noqa: E402 + + +def get_module_spec(): + mutually_exclusive = [("name", "uuid")] + entity_by_spec = dict(name=dict(type="str"), uuid=dict(type="str")) + resource_limit = dict( + resource_type=dict( + type="str", required=True, choices=["VCPUS", "MEMORY", "STORAGE"] + ), + limit=dict(type="int", required=True), + ) + module_args = dict( + name=dict(type="str", required=False), + project_uuid=dict(type="str", required=False), + desc=dict(type="str", required=False), + resource_limits=dict( + type="list", elements="dict", options=resource_limit, required=False + ), + default_subnet=dict( + type="dict", + options=entity_by_spec, + mutually_exclusive=mutually_exclusive, + required=False, + ), + subnets=dict( + type="list", + elements="dict", + options=entity_by_spec, + mutually_exclusive=mutually_exclusive, + required=False, + ), + clusters=dict(type="list", elements="str", required=False), + users=dict(type="list", elements="str", required=False), + external_user_groups=dict(type="list", elements="str", required=False), + ) + return module_args + + +def create_project(module, result): + projects = Project(module) + name = module.params["name"] + if projects.get_uuid(name): + module.fail_json(msg="Project with given name already exists", **result) + + spec, error = projects.get_spec() + if error: + result["error"] = error + module.fail_json(msg="Failed generating create project spec", **result) + if module.check_mode: + result["response"] = spec + return + + resp = projects.create(spec) + project_uuid = resp["metadata"]["uuid"] + task_uuid = resp["status"]["execution_context"]["task_uuid"] + result["project_uuid"] = project_uuid + result["changed"] = True + + if module.params.get("wait"): + task = Task(module) + task.wait_for_completion(task_uuid) + resp = projects.read(project_uuid) + + result["response"] = resp + + +def update_project(module, result): + uuid = module.params["project_uuid"] + if not uuid: + result["error"] = "Missing parameter project_uuid in playbook" + module.fail_json(msg="Failed updating project", **result) + result["project_uuid"] = uuid + + projects = Project(module) + resp = projects.read(uuid) + utils.strip_extra_attrs(resp["status"], resp["spec"]) + resp["spec"] = resp.pop("status") + + update_spec, error = projects.get_spec(resp) + if error: + result["error"] = error + module.fail_json(msg="Failed generating project update spec", **result) + + # check for idempotency + if resp == update_spec: + result["skipped"] = True + module.exit_json(msg="Nothing to update.") + + if module.check_mode: + result["response"] = update_spec + return + + resp = projects.update(update_spec, uuid=uuid) + task_uuid = resp["status"]["execution_context"]["task_uuid"] + + if module.params.get("wait"): + task = Task(module) + task.wait_for_completion(task_uuid) + resp = projects.read(uuid) + + result["changed"] = True + result["response"] = resp + + +def delete_project(module, result): + uuid = module.params["project_uuid"] + if not uuid: + result["error"] = "Missing parameter project_uuid" + module.fail_json(msg="Failed deleting Project", **result) + + projects = Project(module) + resp = projects.delete(uuid) + result["response"] = resp + result["changed"] = True + task_uuid = resp["status"]["execution_context"]["task_uuid"] + + if module.params.get("wait"): + task = Task(module) + resp = task.wait_for_completion(task_uuid) + result["response"] = resp + + +def run_module(): + module = BaseModule( + argument_spec=get_module_spec(), + supports_check_mode=True, + required_if=[ + ("state", "present", ("project_uuid", "name"), True), + ("state", "absent", ("project_uuid",)), + ], + ) + utils.remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None, "project_uuid": None} + if module.params["state"] == "present": + if module.params.get("project_uuid"): + update_project(module, result) + else: + create_project(module, result) + else: + delete_project(module, result) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_projects_info.py b/plugins/modules/ntnx_projects_info.py new file mode 100644 index 000000000..7a5128dd1 --- /dev/null +++ b/plugins/modules/ntnx_projects_info.py @@ -0,0 +1,210 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_projects_info +short_description: projects info module +version_added: 1.4.0 +description: 'Get projects info' +options: + kind: + description: + - The kind name + type: str + default: project + project_uuid: + description: + - project UUID + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Pradeepsingh Bhati (@bhati-pradeep) +""" +EXAMPLES = r""" +- name: List project using name filter criteria + ntnx_projects_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + filter: + name: "test-ansible-project-7" + +- name: List all projects + ntnx_projects_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + register: result + +- name: List project using project uuid criteria + ntnx_projects_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + project_uuid: "" + register: result + +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: + - Metadata for project list output using uuid + - Below response is when we use project_uuid for getting info + returned: always + type: dict + sample: { + "categories": {}, + "categories_mapping": {}, + "creation_time": "2022-07-15T10:59:25Z", + "kind": "project", + "last_update_time": "2022-07-15T10:59:26Z", + "owner_reference": { + "kind": "user", + "name": "admin", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "project_reference": { + "kind": "project", + "name": "integration_test_project", + "uuid": "csb38ebbf-de15-4239-8197-cedcf27ec88d" + }, + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 0, + "uuid": "csb38ebbf-de15-4239-8197-cedcf27ec88d" + } +spec: + description: + - given project spec response + - below response is when we use project_uuid for getting info + returned: always + type: dict + sample: { + "name": "integration_test_project", + "resources": { + "external_user_group_reference_list": [], + "subnet_reference_list": [ + { + "kind": "subnet", + "uuid": "f1c7a142-ed69-4077-9385-ee34dd6a3532" + } + ], + "user_reference_list": [] + } + } +status: + description: + - given project status response + - below response is when we use project_uuid for getting info + returned: always + type: dict + sample: { + "description": "", + "execution_context": { + "task_uuid": [ + "2ad6sea7-9739-4fe9-97cc-87acb67341d7" + ] + }, + "name": "integration_test_project", + "resources": { + "account_reference_list": [], + "cluster_reference_list": [], + "environment_reference_list": [], + "external_network_list": [], + "external_user_group_reference_list": [], + "is_default": false, + "resource_domain": { + "resources": [] + }, + "subnet_reference_list": [ + { + "kind": "subnet", + "name": "xx-xxx", + "uuid": "f1b7c142-ed69-4077-9385-ee34dd6a3532" + } + ], + "tunnel_reference_list": [], + "user_reference_list": [], + "vpc_reference_list": [] + }, + "state": "COMPLETE" + } +""" + + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.projects import Project # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + project_uuid=dict(type="str"), + kind=dict(type="str", default="project"), + sort_order=dict(type="str"), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_project(module, result): + projects = Project(module) + uuid = module.params.get("project_uuid") + resp = projects.read(uuid) + result["response"] = resp + + +def get_projects(module, result): + projects = Project(module) + spec, err = projects.get_info_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating projects info Spec", **result) + resp = projects.list(spec) + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + mutually_exclusive=[ + ("project_uuid", "filter"), + ], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("project_uuid"): + get_project(module, result) + else: + get_projects(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_roles.py b/plugins/modules/ntnx_roles.py new file mode 100644 index 000000000..0012e6271 --- /dev/null +++ b/plugins/modules/ntnx_roles.py @@ -0,0 +1,314 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_roles +short_description: module which supports role CRUD operations +version_added: 1.4.0 +description: "Create, Update, Delete Nutanix roles" +options: + state: + description: + - when C(state)=present and role uuid is not given then it will create new role + - when C(state)=present and role uuid given then it will update the role + - when C(state)=absent, it will delete the role + name: + description: + - name of the role + - allowed to update + - required for creating role + required: false + type: str + role_uuid: + description: + - uuid of the role + - only required while updating or deleting + required: false + type: str + desc: + description: + - description of role + - allowed to update + required: false + type: str + permissions: + description: + - list of details of permission to be added in role + - required while creating new role + - allowed to update + - more than or equal to one permission is always required, empty list is not considered + - during update, if used, it will override the permission list of role + required: false + type: list + elements: dict + suboptions: + uuid: + type: str + description: + - permission uuid. + - Mutually exclusive with C(name). + name: + description: + - permission name. + - Mutually exclusive with C(uuid). + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_operations +author: + - Prem Karat (@premkarat) + - Pradeepsingh Bhati (@bhati-pradeep) +""" + +EXAMPLES = r""" + +- name: Create roles with permissions + ntnx_roles: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + state: present + name: test-ansible-role-1 + desc: test-ansible-role-1-desc + permissions: + - name: "" + - uuid: "" + - uuid: "" + wait: true + register: result + +- name: delete role + ntnx_roles: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + state: absent + role_uuid: "" + register: result +""" + +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: The role kind metadata from creation of new role + returned: always + type: dict + sample: { + "categories": {}, + "categories_mapping": {}, + "creation_time": "2022-07-26T08:25:00Z", + "entity_version": "", + "kind": "role", + "last_update_time": "2022-07-26T08:25:01Z", + "owner_reference": { + "kind": "user", + "name": "admin", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 0, + "uuid": "5d7bv3ab-d825-4cfd-879c-ec7a86a82cfd" + } +spec: + description: An intentful representation of a role spec from creation of new role + returned: always + type: dict + sample: { + "description": "check123", + "name": "test-ansible", + "resources": { + "permission_reference_list": [ + { + "kind": "permission", + "uuid": "190951de-26f1-4caf-760d-df81c3c2jn3j2" + }, + { + "kind": "permission", + "uuid": "fcf661c5-2253-44a9-7ddd-e10c23424324" + } + ] + } + } +status: + description: An intentful representation of a role status from creation of role + returned: always + type: dict + sample: { + "description": "check123", + "execution_context": { + "task_uuid": [ + "asdasdsd-3e01-42e3-9276-d75571273f89" + ] + }, + "is_system_defined": false, + "name": "test-ansible", + "resources": { + "permission_reference_list": [ + { + "kind": "permission", + "name": "perm1", + "uuid": "190951de-26f1-4caf-760d-df81c3c2jn3j2" + }, + { + "kind": "permission", + "name": "perm2", + "uuid": "fcf661c5-2253-44a9-7ddd-e10c23424324" + } + ] + }, + "state": "COMPLETE" + } +role_uuid: + description: The created role uuid + returned: always + type: str + sample: "5d7bv3ab-d825-4cfd-879c-ec7a86a82cfd" +""" + +from ..module_utils import utils # noqa: E402 +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.roles import Role # noqa: E402 +from ..module_utils.prism.tasks import Task # noqa: E402 + + +def get_module_spec(): + mutually_exclusive = [("name", "uuid")] + entity_by_spec = dict(name=dict(type="str"), uuid=dict(type="str")) + module_args = dict( + name=dict(type="str", required=False), + role_uuid=dict(type="str", required=False), + desc=dict(type="str", required=False), + permissions=dict( + type="list", + elements="dict", + options=entity_by_spec, + mutually_exclusive=mutually_exclusive, + required=False, + ), + ) + return module_args + + +def create_role(module, result): + roles = Role(module) + name = module.params["name"] + if roles.get_uuid(name): + module.fail_json(msg="Role with given name already exists", **result) + + spec, err = roles.get_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating create Roles Spec", **result) + + if module.check_mode: + result["response"] = spec + return + + resp = roles.create(data=spec) + task_uuid = resp["status"]["execution_context"]["task_uuid"] + role_uuid = resp["metadata"]["uuid"] + result["role_uuid"] = role_uuid + result["changed"] = True + + if module.params.get("wait"): + tasks = Task(module) + tasks.wait_for_completion(task_uuid) + resp = roles.read(uuid=role_uuid) + result["response"] = resp + + +def update_role(module, result): + roles = Role(module) + role_uuid = module.params.get("role_uuid") + result["role_uuid"] = role_uuid + + resp = roles.read(uuid=role_uuid) + utils.strip_extra_attrs(resp["status"], resp["spec"]) + resp["spec"] = resp.pop("status") + + update_spec, error = roles.get_spec(resp) + if error: + result["error"] = error + module.fail_json(msg="Failed generating Role update spec", **result) + + # check for idempotency + if resp == update_spec: + result["skipped"] = True + module.exit_json(msg="Nothing to change.") + + if module.check_mode: + result["response"] = update_spec + return + + resp = roles.update(data=update_spec, uuid=role_uuid) + task_uuid = resp["status"]["execution_context"]["task_uuid"] + result["changed"] = True + + if module.params.get("wait"): + tasks = Task(module) + tasks.wait_for_completion(task_uuid) + resp = roles.read(uuid=role_uuid) + + result["response"] = resp + + +def delete_role(module, result): + roles = Role(module) + role_uuid = module.params["role_uuid"] + resp = roles.delete(uuid=role_uuid) + task_uuid = resp["status"]["execution_context"]["task_uuid"] + result["changed"] = True + + if module.params.get("wait"): + tasks = Task(module) + resp = tasks.wait_for_completion(task_uuid) + result["response"] = resp + + +def run_module(): + module = BaseModule( + argument_spec=get_module_spec(), + supports_check_mode=True, + required_if=[ + ("state", "present", ("name", "role_uuid"), True), + ("state", "absent", ("role_uuid",)), + ], + ) + utils.remove_param_with_none_value(module.params) + result = { + "changed": False, + "error": None, + "response": None, + "role_uuid": None, + } + state = module.params["state"] + if state == "present": + if module.params.get("role_uuid"): + update_role(module, result) + else: + create_role(module, result) + elif state == "absent": + delete_role(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_roles_info.py b/plugins/modules/ntnx_roles_info.py new file mode 100644 index 000000000..d616d5030 --- /dev/null +++ b/plugins/modules/ntnx_roles_info.py @@ -0,0 +1,206 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_roles_info +short_description: role info module +version_added: 1.4.0 +description: 'Get roles info' +options: + kind: + description: + - The kind name + type: str + default: role + role_uuid: + description: + - role UUID + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Pradeepsingh Bhati (@bhati-pradeep) +""" +EXAMPLES = r""" +- name: List all roles + ntnx_roles_info: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + register: result + +- name: List role using uuid criteria + ntnx_roles_info: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + role_uuid: "{{ test_role_uuid }}" + register: result + +- name: List roles using filter criteria + ntnx_roles_info: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + filter: + name: "{{ test_role_name }}" +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: + - Metadata for role list output + - Below struct is only obtained when we use filters or list roles using length, etc. + returned: always + type: dict + sample: { + "kind": "role", + "length": 1, + "offset": 0, + "total_matches": 14 + } +entities: + description: + - entities intent response + - Below struct is only obtained when we use filters or list roles using length, etc. + returned: always + type: list + sample: [ + { + "metadata": { + "categories": {}, + "categories_mapping": {}, + "creation_time": "2022-07-26T08:25:00Z", + "entity_version": "", + "kind": "role", + "last_update_time": "2022-07-26T08:25:01Z", + "owner_reference": { + "kind": "user", + "name": "admin", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 0, + "uuid": "ansnjs74-d825-4cfd-879c-ec7a86a82cfd" + }, + "spec": { + "description": "check123-updated", + "name": "test-ansible-1-updated-1-2-3", + "resources": { + "permission_reference_list": [ + { + "kind": "permission", + "uuid": "nsjd51de-26f1-4caf-760d-df81c3ca8a88" + }, + { + "kind": "permission", + "uuid": "sheusjdf-2253-44a9-7ddd-e10c53a4ad04" + } + ] + } + }, + "status": { + "description": "check123-updated", + "execution_context": { + "task_uuid": [ + "29s6heyd-3e01-42e3-9276-d75571273f89" + ] + }, + "is_system_defined": false, + "name": "test-ansible-1-updated-1-2-3", + "resources": { + "permission_reference_list": [ + { + "kind": "permission", + "name": "perm1", + "uuid": "nsjd51de-26f1-4caf-760d-df81c3ca8a88" + }, + { + "kind": "permission", + "name": "perm2", + "uuid": "sheusjdf-2253-44a9-7ddd-e10c53a4ad04" + } + ] + }, + "state": "COMPLETE" + } + } + ] +""" + + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.roles import Role # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + role_uuid=dict(type="str"), + kind=dict(type="str", default="role"), + sort_order=dict(type="str"), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_role(module, result): + roles = Role(module) + uuid = module.params.get("role_uuid") + resp = roles.read(uuid) + result["response"] = resp + + +def get_roles(module, result): + roles = Role(module) + spec, err = roles.get_info_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating Roles info Spec", **result) + resp = roles.list(spec) + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + mutually_exclusive=[ + ("role_uuid", "filter"), + ], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("role_uuid"): + get_role(module, result) + else: + get_roles(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_security_rules.py b/plugins/modules/ntnx_security_rules.py index c8b024f65..6f712a21e 100644 --- a/plugins/modules/ntnx_security_rules.py +++ b/plugins/modules/ntnx_security_rules.py @@ -1235,7 +1235,7 @@ def update_security_rule(module, result): security_rule = SecurityRule(module) resp = security_rule.read(security_rule_uuid) result["response"] = resp - utils.strip_extra_attrs_from_status(resp["status"], resp["spec"]) + utils.strip_extra_attrs(resp["status"], resp["spec"]) resp.pop("status") spec, error = security_rule.get_spec(resp) diff --git a/plugins/modules/ntnx_security_rules_info.py b/plugins/modules/ntnx_security_rules_info.py index 96b6345cc..30ac5fec5 100644 --- a/plugins/modules/ntnx_security_rules_info.py +++ b/plugins/modules/ntnx_security_rules_info.py @@ -45,7 +45,8 @@ nutanix_username: "{{ username }}" nutanix_password: "{{ password }}" validate_certs: False - filter: "name=={{ security_rule.name }}" + filter: + name: "{{ security_rule.name }}" kind: security_rule register: result diff --git a/plugins/modules/ntnx_service_groups.py b/plugins/modules/ntnx_service_groups.py new file mode 100644 index 000000000..14d01d454 --- /dev/null +++ b/plugins/modules/ntnx_service_groups.py @@ -0,0 +1,278 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_service_groups +short_description: service_groups module which suports service_groups CRUD operations +version_added: 1.4.0 +description: 'Create, Update, Delete service_group' +options: + state: + description: + - Specify state of service_groups + - If C(state) is set to C(present) then service_groups is created. + - >- + If C(state) is set to C(absent) and if the service_groups exists, then + service_groups is removed. + choices: + - present + - absent + type: str + default: present + wait: + description: Wait for service_groups CRUD operation to complete. + type: bool + required: false + default: True + name: + description: service_groups Name + required: False + type: str + service_group_uuid: + description: service_group UUID + type: str + desc: + description: service_groups description + type: str + service_details: + type: dict + description: List of port, protocol or icmp codes + suboptions: + any_icmp: + description: any icmp code or type + type: bool + default: false + tcp: + description: List of TCP ports in the service + type: list + elements: str + udp: + description: List of UDP ports in the service + type: list + elements: str + icmp: + description: List of ICMP types and codes in the service + type: list + elements: dict + suboptions: + code: + type: int + description: ICMP code + type: + description: ICMP type + type: int +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_operations +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" + +EXAMPLES = r""" +- name: create service group with tcp and udp and icmp + ntnx_service_groups: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + name: app_srvive_group + desc: desc + service_details: + tcp: + - "*" + udp: + - "10-50" + - "60-90" + - "99" + any_icmp: True + register: result + +- name: create service group with icmp + ntnx_service_groups: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + name: icmp_srvive_group + desc: desc + service_details: + icmp: + - code: 10 + - type: 1 + - type: 2 + code: 3 + register: result + +- name: update tcp service group name and description and other protocols + ntnx_service_groups: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + service_group_uuid: "{{service_group_uuid}}" + name: updated_name + desc: updated_desc + service_details: + tcp: + - "60-90" + icmp: + - type: 2 + code: 3 + register: result +""" + +RETURN = r""" +service_group_uuid: + description: The created service group uuid + returned: always + type: str + sample: 00000000000-0000-0000-0000-00000000000 +kind: + description: The service group kind name + returned: always + type: str + sample: service_group +""" + +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.service_groups import ServiceGroup # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + icmp_spec = dict(code=dict(type="int"), type=dict(type="int")) + + service_spec = dict( + tcp=dict(type="list", elements="str"), + udp=dict(type="list", elements="str"), + icmp=dict( + type="list", + elements="dict", + options=icmp_spec, + ), + any_icmp=dict(type="bool", default=False), + ) + + module_args = dict( + name=dict(type="str"), + desc=dict(type="str"), + service_group_uuid=dict(type="str"), + service_details=dict( + type="dict", options=service_spec, mutually_exclusive=[("icmp", "any_icmp")] + ), + ) + + return module_args + + +def create_service_group(module, result): + service_group = ServiceGroup(module) + spec, error = service_group.get_spec() + if error: + result["error"] = error + module.fail_json(msg="Failed generating service_groups spec", **result) + + if module.check_mode: + result["response"] = spec + return + + resp = service_group.create(spec) + service_group_uuid = resp["uuid"] + result["changed"] = True + result["response"] = resp + result["service_group_uuid"] = service_group_uuid + + +def update_service_group(module, result): + service_group = ServiceGroup(module) + service_group_uuid = module.params.get("service_group_uuid") + if not service_group_uuid: + result["error"] = "Missing parameter service_group_uuid in playbook" + module.fail_json(msg="Failed updating service_group", **result) + result["service_group_uuid"] = service_group_uuid + + # read the current state of service_group + resp = service_group.read(service_group_uuid) + resp = resp.get("service_group") + + # new spec for updating service_group + update_spec, error = service_group.get_spec(resp) + if error: + result["error"] = error + module.fail_json(msg="Failed generating service_group update spec", **result) + + # check for idempotency + if resp == update_spec: + result["skipped"] = True + module.exit_json( + msg="Nothing to change. Refer docs to check for fields which can be updated" + ) + + if module.check_mode: + result["response"] = update_spec + return + + # update service_group + service_group.update(update_spec, uuid=service_group_uuid, no_response=True) + + resp = service_group.read(service_group_uuid) + + result["changed"] = True + result["response"] = resp + + +def delete_service_group(module, result): + service_group_uuid = module.params["service_group_uuid"] + if not service_group_uuid: + result["error"] = "Missing parameter service_group_uuid in playbook" + module.fail_json(msg="Failed deleting service_groups", **result) + + service_group = ServiceGroup(module) + resp = service_group.delete(service_group_uuid, no_response=True) + result["changed"] = True + result["response"] = resp + result["service_group_uuid"] = service_group_uuid + + +def run_module(): + module = BaseModule( + argument_spec=get_module_spec(), + supports_check_mode=True, + required_if=[ + ("state", "present", ("name", "service_group_uuid"), True), + ("state", "absent", ("service_group_uuid",)), + ], + ) + remove_param_with_none_value(module.params) + result = { + "changed": False, + "error": None, + "response": None, + "service_group_uuid": None, + } + state = module.params["state"] + if state == "absent": + delete_service_group(module, result) + elif module.params.get("service_group_uuid"): + update_service_group(module, result) + else: + create_service_group(module, result) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_service_groups_info.py b/plugins/modules/ntnx_service_groups_info.py new file mode 100644 index 000000000..7fe0c0a6d --- /dev/null +++ b/plugins/modules/ntnx_service_groups_info.py @@ -0,0 +1,198 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_service_groups_info +short_description: service_group info module +version_added: 1.4.0 +description: 'Get service_group info' +options: + kind: + description: + - The kind name + type: str + default: service_group + service_group_uuid: + description: + - service_group UUID + type: str + sort_order: + description: + - The sort order in which results are returned + type: str + choices: + - ASCENDING + - DESCENDING +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" +EXAMPLES = r""" + - name: List service_group using name filter criteria + ntnx_service_groups_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + filter: + name: "{{ service_group.name }}" + kind: service_group + register: result + + - name: List service_group using length, offset, sort order and name sort attribute + ntnx_service_groups_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + length: 1 + offset: 1 + sort_order: "ASCENDING" + sort_attribute: "name" + register: result +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: Metadata for service_group_info list output + returned: always + type: dict + sample: { + "metadata": { + "kind": "service_group", + "length": 1, + "offset": 2, + "sort_attribute": "name", + "sort_order": "DESCENDING", + "total_matches": 3 + } } +entities: + description: service_group intent response + returned: always + type: list + sample: { + "entities": [ + {"service_group": { + "description": "desc", + "is_system_defined": false, + "name": "test_service", + "service_list": [ + { + "protocol": "TCP", + "tcp_port_range_list": [ + { + "end_port": 23, + "start_port": 0 + } + ] + }, + { + "protocol": "UDP", + "udp_port_range_list": [ + { + "end_port": 50, + "start_port": 10 + }, + { + "end_port": 90, + "start_port": 60 + }, + { + "end_port": 99, + "start_port": 99 + } + ] + }, + { + "icmp_type_code_list": [ + { + "code": 10 + }, + { + "type": 1 + }, + { + "code": 3, + "type": 2 + } + ], + "protocol": "ICMP" + } + ] + }, + "uuid": "00000000-0000-0000-0000-000000000000" + } + ] + } +""" + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.service_groups import ServiceGroup # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + service_group_uuid=dict(type="str"), + kind=dict(type="str", default="service_group"), + sort_order=dict(type="str", choices=["ASCENDING", "DESCENDING"]), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_service_group(module, result): + service_group = ServiceGroup(module) + service_group_uuid = module.params.get("service_group_uuid") + resp = service_group.read(service_group_uuid) + + result["response"] = resp + + +def get_service_groups(module, result): + service_group = ServiceGroup(module) + spec, error = service_group.get_info_spec() + + resp = service_group.list(spec) + + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("service_group_uuid"): + get_service_group(module, result) + else: + get_service_groups(module, result) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_static_routes.py b/plugins/modules/ntnx_static_routes.py index ba29c3fc7..edc2e0504 100644 --- a/plugins/modules/ntnx_static_routes.py +++ b/plugins/modules/ntnx_static_routes.py @@ -271,11 +271,11 @@ """ from ..module_utils.base_module import BaseModule # noqa: E402 -from ..module_utils.prism.static_routes import StaticRoutes # noqa: E402 +from ..module_utils.prism.static_routes import StaticRoute # noqa: E402 from ..module_utils.prism.tasks import Task # noqa: E402 from ..module_utils.utils import ( # noqa: E402 remove_param_with_none_value, - strip_extra_attrs_from_status, + strip_extra_attrs, ) @@ -317,8 +317,29 @@ def get_module_spec(): return module_args +def check_static_routes_idempotency(routes1, routes2): + # check default route + if routes1["spec"]["resources"].get("default_route_nexthop") != routes2["spec"][ + "resources" + ].get("default_route_nexthop"): + return False + + # check static routes length + if len(routes1["spec"]["resources"]["static_routes_list"]) != len( + routes2["spec"]["resources"]["static_routes_list"] + ): + return False + + # check static routes contents + for route in routes1["spec"]["resources"]["static_routes_list"]: + if route not in routes2["spec"]["resources"]["static_routes_list"]: + return False + + return True + + def update_static_routes(module, result): - static_routes = StaticRoutes(module) + static_routes = StaticRoute(module) vpc_uuid = module.params["vpc_uuid"] curr_routes = static_routes.get_static_routes(vpc_uuid) result["response"] = curr_routes @@ -330,7 +351,7 @@ def update_static_routes(module, result): "status" ]["resources"]["default_route"]["nexthop"] - strip_extra_attrs_from_status(curr_routes["status"], curr_routes["spec"]) + strip_extra_attrs(curr_routes["status"], curr_routes["spec"]) curr_routes["spec"] = curr_routes.pop("status") # new spec for updating static routes @@ -339,14 +360,12 @@ def update_static_routes(module, result): result["error"] = err module.fail_json(msg="Failed generating static routes update spec", **result) - if update_spec == curr_routes: + if check_static_routes_idempotency(curr_routes, update_spec): result["skipped"] = True module.exit_json(msg="Nothing to update") if module.check_mode: result["response"] = update_spec - result["params"] = module.params - result["current_spec"] = curr_routes return # update static routes diff --git a/plugins/modules/ntnx_static_routes_info.py b/plugins/modules/ntnx_static_routes_info.py index db935ad73..4e825e5d8 100644 --- a/plugins/modules/ntnx_static_routes_info.py +++ b/plugins/modules/ntnx_static_routes_info.py @@ -167,7 +167,7 @@ """ from ..module_utils.base_module import BaseModule # noqa: E402 -from ..module_utils.prism.static_routes import StaticRoutes # noqa: E402 +from ..module_utils.prism.static_routes import StaticRoute # noqa: E402 def get_module_spec(): @@ -181,7 +181,7 @@ def get_module_spec(): def get_static_routes(module, result): vpc_uuid = module.params["vpc_uuid"] - static_routes = StaticRoutes(module) + static_routes = StaticRoute(module) result["response"] = static_routes.get_static_routes(vpc_uuid) result["vpc_uuid"] = vpc_uuid diff --git a/plugins/modules/ntnx_subnets_info.py b/plugins/modules/ntnx_subnets_info.py index f0662d451..99e7fcab5 100644 --- a/plugins/modules/ntnx_subnets_info.py +++ b/plugins/modules/ntnx_subnets_info.py @@ -39,7 +39,8 @@ nutanix_username: "{{ username }}" nutanix_password: "{{ password }}" validate_certs: False - filter: "subnet_type=={{ subnet.type }}" + filter: + subnet_type: "{{ subnet.type }}" kind: subnet register: result diff --git a/plugins/modules/ntnx_user_groups.py b/plugins/modules/ntnx_user_groups.py new file mode 100644 index 000000000..a86f8d1da --- /dev/null +++ b/plugins/modules/ntnx_user_groups.py @@ -0,0 +1,299 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_user_groups +short_description: user_groups module which supports pc user_groups management create delete operations +version_added: 1.4.0 +description: "Create, Delete user_groups" +options: + state: + description: + - Specify state + - If C(state) is set to C(present) then the operation will be create the item. + - if C(state) is set to C(present) and C(user_group_uuid) is given then it will update that user_group. + - >- + If C(state) is set to C(absent) and if the item exists, then + item is removed. + choices: + - present + - absent + type: str + default: present + wait: + description: Wait for the CRUD operation to complete. + type: bool + required: false + default: True + distinguished_name: + description: user_group name + required: false + type: str + user_group_uuid: + description: user_group uuid + type: str + required: false + categories: + description: + - Categories for the user_group. This allows setting up multiple values from a single key. + - this will override existing categories with mentioned during update + - mutually_exclusive with C(remove_categories) + required: false + type: dict + remove_categories: + description: + - set this flag to remove dettach all categories attached to user_group + - mutually_exclusive with C(categories) + type: bool + required: false + default: false + idp: + type: dict + description: An Identity Provider user + suboptions: + idp_uuid: + type: str + required: true + description: An Identity Provider user uuid + group_name: + type: str + required: true + description: group name + project: + type: dict + description: project that belongs to + suboptions: + name: + type: str + description: project name + uuid: + type: str + description: project uuid +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_operations +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" + +EXAMPLES = r""" +- name: create image from local workstation + ntnx_images: + +- name: create user group + ntnx_user_groups: + state: "present" + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + distinguished_name: "" + project: + uuid: "{{project_uuid}}" + categories: + Environment: + - "Dev" + register: result + +- name: create user group with idp + ntnx_user_groups: + state: "present" + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + idp: + idp_uuid: "{{idp_uuid}}" + group_name: "{{group_name}}" + register: result +""" + +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: The user_group kind metadata + returned: always + type: dict + sample: { + "categories": {}, + "categories_mapping": {}, + "kind": "user_group", + "owner_reference": { + "kind": "user", + "name": "admin", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 0, + "uuid": "00000000-0000-0000-0000-000000000000" + + } +spec: + description: An intentful representation of a user_group spec + returned: always + type: dict + sample: { + "resources": { + "directory_service_user_group": { + "distinguished_name": "" + } + } + + } +status: + description: An intentful representation of a user_group status + returned: always + type: dict + sample: { +"execution_context": { + "task_uuid": [ + "00000000-0000-0000-0000-000000000000" + ] + }, + "resources": { + "access_control_policy_reference_list": [], + "directory_service_user_group": { + "directory_service_reference": { + "kind": "directory_service", + "name": "ds", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "distinguished_name": "" + }, + "display_name": "", + "projects_reference_list": [], + "user_group_type": "DIRECTORY_SERVICE" + }, + "state": "COMPLETE" + + } +user_group_uuid: + description: The created user_group uuid + returned: always + type: str + sample: "00000000-0000-0000-0000-000000000000" +""" + +from ..module_utils import utils # noqa: E402 +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.tasks import Task # noqa: E402 +from ..module_utils.prism.user_groups import UserGroup # noqa: E402 + + +def get_module_spec(): + + mutually_exclusive = [("name", "uuid")] + + entity_by_spec = dict(name=dict(type="str"), uuid=dict(type="str")) + + saml_user_group_spec = dict( + idp_uuid=dict(type="str", required=True), + group_name=dict(type="str", required=True), + ) + + module_args = dict( + user_group_uuid=dict(type="str"), + distinguished_name=dict(type="str"), + idp=dict(type="dict", options=saml_user_group_spec), + project=dict( + type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive + ), + remove_categories=dict(type="bool", default=False), + categories=dict(type="dict", required=False), + ) + return module_args + + +def create_user_group(module, result): + user_group = UserGroup(module) + spec, error = user_group.get_spec() + if error: + result["error"] = error + module.fail_json(msg="Failed generating create user_group Spec", **result) + if module.check_mode: + result["response"] = spec + return + + # create user_group + resp = user_group.create(spec) + user_group_uuid = resp["metadata"]["uuid"] + task_uuid = resp["status"]["execution_context"]["task_uuid"] + result["user_group_uuid"] = user_group_uuid + result["changed"] = True + + if module.params.get("wait"): + task = Task(module) + task.wait_for_completion(task_uuid) + # get the user_group + resp = user_group.read(user_group_uuid) + + result["response"] = resp + + +def delete_user_group(module, result): + uuid = module.params["user_group_uuid"] + if not uuid: + result["error"] = "Missing parameter user_group_uuid" + module.fail_json(msg="Failed deleting user_group", **result) + + user_group = UserGroup(module) + resp = user_group.delete(uuid) + result["response"] = resp + result["changed"] = True + task_uuid = resp["status"]["execution_context"]["task_uuid"] + + if module.params.get("wait"): + task = Task(module) + resp = task.wait_for_completion(task_uuid) + result["response"] = resp + + +def run_module(): + # mutually_exclusive_list have params which are not allowed together + mutually_exclusive_list = [ + ("categories", "remove_categories"), + ("distinguished_name", "idp"), + ] + module = BaseModule( + argument_spec=get_module_spec(), + supports_check_mode=True, + required_if=[ + ("state", "absent", ("user_group_uuid",)), + ], + mutually_exclusive=mutually_exclusive_list, + ) + utils.remove_param_with_none_value(module.params) + result = { + "changed": False, + "error": None, + "response": None, + "user_group_uuid": None, + } + state = module.params["state"] + if state == "present": + create_user_group(module, result) + else: + delete_user_group(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_user_groups_info.py b/plugins/modules/ntnx_user_groups_info.py new file mode 100644 index 000000000..0c0875e31 --- /dev/null +++ b/plugins/modules/ntnx_user_groups_info.py @@ -0,0 +1,228 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_user_groups_info +short_description: User Groups info module +version_added: 1.4.0 +description: 'Get User Groups info' +options: + kind: + description: + - The kind name + type: str + default: user_group + usergroup_uuid: + description: + - user group UUID + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" +EXAMPLES = r""" + - name: List user groups using name filter criteria + ntnx_user_groups_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + filter: + group_name: "{{ name }}" + register: result + + - name: List user groups using length, offset, sort order and sort attribute + ntnx_user_groups_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + length: 2 + offset: 1 + sort_order: "DESCENDING" + sort_attribute: "group_name" + register: result + + - name: test getting particular user group using uuid + ntnx_user_groups_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + usergroup_uuid: '{{ uuid }}' + register: result +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: Metadata for user groups list output + returned: always + type: dict + sample: { + "filter": "group_name=={{name}}", + "kind": "user", + "length": 2, + "offset": 0, + "total_matches": 2 + } +entities: + description: user groups intent response + returned: always + type: list + sample: [ + { + "metadata": { + "categories": {}, + "categories_mapping": {}, + "kind": "user_group", + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 0, + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "spec": { + "resources": { + "directory_service_user_group": { + "distinguished_name": "CN=test_custom_{_group_},CN=Users,DC=ad,DC=ds,DC=io" + } + } + }, + "status": { + "execution_context": { + "task_uuid": [ + "00000000-0000-0000-0000-000000000000" + ] + }, + "resources": { + "access_control_policy_reference_list": [], + "directory_service_user_group": { + "directory_service_reference": { + "kind": "directory_service", + "name": "ds", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "distinguished_name": "cn=test_custom_{_group_},cn=users,dc=ad,dc=ds,dc=io" + }, + "display_name": "test_custom_{_group_}", + "projects_reference_list": [], + "user_group_type": "DIRECTORY_SERVICE" + }, + "state": "COMPLETE" + } + }, + { + "metadata": { + "categories": {}, + "categories_mapping": {}, + "kind": "user_group", + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 1, + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "spec": { + "resources": { + "directory_service_user_group": { + "distinguished_name": "" + } + } + }, + "status": { + "execution_context": { + "task_uuid": [ + "00000000-0000-0000-0000-000000000000" + ] + }, + "resources": { + "access_control_policy_reference_list": [], + "directory_service_user_group": { + "directory_service_reference": { + "kind": "directory_service", + "name": "qanucalm", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "distinguished_name": "" + }, + "display_name": "name1", + "projects_reference_list": [], + "user_group_type": "DIRECTORY_SERVICE" + }, + "state": "PENDING" + } + } + ] +""" + + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.user_groups import UserGroup # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + usergroup_uuid=dict(type="str"), + kind=dict(type="str", default="user_group"), + sort_order=dict(type="str"), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_user_group(module, result): + user_group = UserGroup(module) + uuid = module.params.get("usergroup_uuid") + resp = user_group.read(uuid) + result["response"] = resp + + +def get_user_groups(module, result): + user_group = UserGroup(module) + spec, err = user_group.get_info_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating user groups info Spec", **result) + resp = user_group.list(spec) + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + mutually_exclusive=[ + ("usergroup_uuid", "filter"), + ], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("usergroup_uuid"): + get_user_group(module, result) + else: + get_user_groups(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_users.py b/plugins/modules/ntnx_users.py new file mode 100644 index 000000000..2c06d8efd --- /dev/null +++ b/plugins/modules/ntnx_users.py @@ -0,0 +1,318 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_users +short_description: users module which supports pc users management create delete operations +version_added: 1.4.0 +description: "Create, Delete users" +options: + state: + description: + - Specify state + - If C(state) is set to C(present) then the operation will be create the item. + - if C(state) is set to C(present) and C(user_uuid) is given then it will update that user. + - >- + If C(state) is set to C(absent) and if the item exists, then + item is removed. + choices: + - present + - absent + type: str + default: present + wait: + description: Wait for the CRUD operation to complete. + type: bool + required: false + default: True + username: + description: user name + required: false + type: str + user_uuid: + description: user uuid + type: str + required: false + categories: + description: + - Categories for the user. This allows setting up multiple values from a single key. + - this will override existing categories with mentioned during update + - mutually_exclusive with C(remove_categories) + required: false + type: dict + remove_categories: + description: + - set this flag to remove dettach all categories attached to user + - mutually_exclusive with C(categories) + type: bool + required: false + default: false + identity_provider_uuid: + type: str + description: The uuid of the identity provider. + directory_service_uuid: + type: str + description: The UUID of the directory service. + principal_name: + type: str + description: The UserPrincipalName of the user from the directory service. + project: + type: dict + description: project that belogs to + suboptions: + name: + type: str + description: project name + uuid: + type: str + description: project uuid +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_operations +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" + +EXAMPLES = r""" +- name: create local user + ntnx_users: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + principal_name: "{{principal_name}}" + directory_service_uuid: "{{directory_service_uuid}}" + project: + uuid: "{{project_uuid}}" + categories: + Environment: + - "Dev" + AppType: + - "Default" + register: result + +- name: create idp user + ntnx_users: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + identity_provider_uuid: "{{identity_provider_uuid}}" + username: "{{username}}" + register: result +""" + +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: The user kind metadata + returned: always + type: dict + sample: { + "categories": { + "AppFamily": "Backup" + }, + "categories_mapping": { + "AppFamily": [ + "Backup" + ] + }, + "creation_time": "2022-06-09T10:13:38Z", + "kind": "user", + "last_update_time": "2022-06-09T10:37:14Z", + "owner_reference": { + "kind": "user", + "name": "admin", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 14, + "uuid": "00000000-0000-0000-0000-000000000000" + } +spec: + description: An intentful representation of a user spec + returned: always + type: dict + sample: { + "resources": { + "directory_service_user": { + "directory_service_reference": { + "kind": "directory_service", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "user_principal_name": "test_custom@qa.nucalm.io" + } + } + } +status: + description: An intentful representation of a user status + returned: always + type: dict + sample: { + "execution_context": { + "task_uuid": [ + "00000000-0000-0000-0000-000000000000" + ] + }, + "name": "test_custom@qa.nucalm.io", + "resources": { + "access_control_policy_reference_list": [], + "directory_service_user": { + "default_user_principal_name": "test_custom@qa.nucalm.io", + "directory_service_reference": { + "kind": "directory_service", + "name": "qanucalm", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "user_principal_name": "test_custom@qa.nucalm.io" + }, + "display_name": null, + "projects_reference_list": [ + { + "kind": "project", + "name": "default", + "uuid": "00000000-0000-0000-0000-000000000000" + } + ], + "resource_usage_summary": { + "resource_domain": { + "resources": [] + } + }, + "user_type": "DIRECTORY_SERVICE" + }, + "state": "COMPLETE" + } + +user_uuid: + description: The created user uuid + returned: always + type: str + sample: "00000000-0000-0000-0000-000000000000" +""" + +from ..module_utils import utils # noqa: E402 +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.tasks import Task # noqa: E402 +from ..module_utils.prism.users import User # noqa: E402 + + +def get_module_spec(): + + mutually_exclusive = [("name", "uuid")] + + entity_by_spec = dict(name=dict(type="str"), uuid=dict(type="str")) + + module_args = dict( + user_uuid=dict(type="str"), + principal_name=dict(type="str"), + username=dict(type="str"), + directory_service_uuid=dict(type="str"), + identity_provider_uuid=dict(type="str"), + project=dict( + type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive + ), + remove_categories=dict(type="bool", default=False), + categories=dict(type="dict", required=False), + ) + return module_args + + +def create_user(module, result): + user = User(module) + spec, error = user.get_spec() + if error: + result["error"] = error + module.fail_json(msg="Failed generating create user Spec", **result) + if module.check_mode: + result["response"] = spec + return + + # create user + resp = user.create(spec) + user_uuid = resp["metadata"]["uuid"] + task_uuid = resp["status"]["execution_context"]["task_uuid"] + result["user_uuid"] = user_uuid + result["changed"] = True + + if module.params.get("wait"): + task = Task(module) + task.wait_for_completion(task_uuid) + # get the user + resp = user.read(user_uuid) + + result["response"] = resp + + +def delete_user(module, result): + uuid = module.params["user_uuid"] + if not uuid: + result["error"] = "Missing parameter user_uuid" + module.fail_json(msg="Failed deleting user", **result) + + user = User(module) + resp = user.delete(uuid) + result["response"] = resp + result["changed"] = True + task_uuid = resp["status"]["execution_context"]["task_uuid"] + + if module.params.get("wait"): + task = Task(module) + resp = task.wait_for_completion(task_uuid) + result["response"] = resp + + +def run_module(): + # mutually_exclusive_list have params which are not allowed together + mutually_exclusive_list = [ + ("categories", "remove_categories"), + ("identity_provider_uuid", "directory_service_uuid"), + ("username", "principal_name"), + ] + module = BaseModule( + argument_spec=get_module_spec(), + supports_check_mode=True, + required_if=[ + ("state", "absent", ("user_uuid",)), + ], + required_together=[ + ("username", "identity_provider_uuid"), + ("principal_name", "directory_service_uuid"), + ], + mutually_exclusive=mutually_exclusive_list, + ) + utils.remove_param_with_none_value(module.params) + result = { + "changed": False, + "error": None, + "response": None, + "user_uuid": None, + } + state = module.params["state"] + if state == "present": + create_user(module, result) + else: + delete_user(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_users_info.py b/plugins/modules/ntnx_users_info.py new file mode 100644 index 000000000..160685af4 --- /dev/null +++ b/plugins/modules/ntnx_users_info.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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: ntnx_users_info +short_description: users info module +version_added: 1.4.0 +description: 'Get users info' +options: + kind: + description: + - The kind name + type: str + default: user + user_uuid: + description: + - user UUID + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Pradeepsingh Bhati (@bhati-pradeep) + - Alaa Bishtawi (@alaa-bish) +""" +EXAMPLES = r""" + - name: List users using name filter criteria + ntnx_users_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + filter: + username: "{{ name }}" + register: result + + - name: List users using length, offset, sort order and sort attribute + ntnx_users_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + length: 2 + offset: 1 + sort_order: "DESCENDING" + sort_attribute: "username" + register: result + + - name: test getting particular user using uuid + ntnx_users_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + user_uuid: '{{ uuid }}' + register: result +""" +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: Metadata for users list output + returned: always + type: dict + sample: { + "filter": "username=={{name}}", + "kind": "user", + "length": 1, + "offset": 0, + "total_matches": 1 + } +entities: + description: users intent response + returned: always + type: list + sample: [ + { + "metadata": { + "categories": {}, + "categories_mapping": {}, + "kind": "user", + "spec_hash": "00000000000000000000000000000000000000000000000000", + "spec_version": 0, + "uuid": "000000-0000-0000-0000-0000000" + }, + "spec": { + "resources": { + "directory_service_user": { + "directory_service_reference": { + "kind": "directory_service", + "uuid": "000000-0000-0000-0000-0000000" + }, + "user_principal_name": "user1@xx.com" + } + } + }, + "status": { + "name": "user1@xx.com", + "resources": { + "access_control_policy_reference_list": [ + { + "kind": "access_control_policy", + "name": "nuCalmAcp-db48cbac-eac8-c384-84f6-3c8376d70db6", + "uuid": "000000-0000-0000-0000-0000000" + } + ], + "directory_service_user": { + "default_user_principal_name": "user1@xx.com", + "directory_service_reference": { + "kind": "directory_service", + "name": "ds", + "uuid": "000000-0000-0000-0000-0000000" + }, + "user_principal_name": "user1@xx.com" + }, + "display_name": null, + "projects_reference_list": [ + { + "kind": "project", + "name": "p1", + "uuid": "000000-0000-0000-0000-0000000" + }, + { + "kind": "project", + "name": "p2", + "uuid": "000000-0000-0000-0000-0000000" + } + ], + "resource_usage_summary": { + "resource_domain": { + "resources": [] + } + }, + "user_type": "DIRECTORY_SERVICE" + }, + "state": "COMPLETE" + } + } + ] +""" + + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.users import User # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + user_uuid=dict(type="str"), + kind=dict(type="str", default="user"), + sort_order=dict(type="str"), + sort_attribute=dict(type="str"), + ) + + return module_args + + +def get_user(module, result): + users = User(module) + uuid = module.params.get("user_uuid") + resp = users.read(uuid) + result["response"] = resp + + +def get_users(module, result): + users = User(module) + spec, err = users.get_info_spec() + if err: + result["error"] = err + module.fail_json(msg="Failed generating User info Spec", **result) + resp = users.list(spec) + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + required_together=[("sort_order", "sort_attribute")], + mutually_exclusive=[ + ("user_uuid", "filter"), + ], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("user_uuid"): + get_user(module, result) + else: + get_users(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/ntnx_vms.py b/plugins/modules/ntnx_vms.py index 49d077c1e..7d1d329d3 100644 --- a/plugins/modules/ntnx_vms.py +++ b/plugins/modules/ntnx_vms.py @@ -857,7 +857,7 @@ def update_vm(module, result): vm = VM(module) resp = vm.read(vm_uuid) result["response"] = resp - utils.strip_extra_attrs_from_status(resp["status"], resp["spec"]) + utils.strip_extra_attrs(resp["status"], resp["spec"]) resp["spec"] = resp.pop("status") spec, error = vm.get_spec(resp) diff --git a/plugins/modules/ntnx_vms_info.py b/plugins/modules/ntnx_vms_info.py index 07f2f9f12..c11ec2904 100644 --- a/plugins/modules/ntnx_vms_info.py +++ b/plugins/modules/ntnx_vms_info.py @@ -39,7 +39,8 @@ nutanix_username: "{{ username }}" nutanix_password: "{{ password }}" validate_certs: False - filter: "vm_name=={{ vm.name }}" + filter: + vm_name: "{{ vm.name }}" kind: vm register: result diff --git a/plugins/modules/ntnx_vpcs_info.py b/plugins/modules/ntnx_vpcs_info.py index 5a9c75e6c..88bd49aa5 100644 --- a/plugins/modules/ntnx_vpcs_info.py +++ b/plugins/modules/ntnx_vpcs_info.py @@ -39,7 +39,8 @@ nutanix_username: "{{ username }}" nutanix_password: "{{ password }}" validate_certs: False - filter: "name=={{ vpc.name }}" + filter: + name: "{{ vpc.name }}" kind: vpc register: result diff --git a/tests/integration/targets/ntnx_acps/aliases b/tests/integration/targets/ntnx_acps/aliases new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/tests/integration/targets/ntnx_acps/aliases @@ -0,0 +1 @@ + diff --git a/tests/integration/targets/ntnx_acps/meta/main.yml b/tests/integration/targets/ntnx_acps/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_acps/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_acps/tasks/create_acps.yml b/tests/integration/targets/ntnx_acps/tasks/create_acps.yml new file mode 100644 index 000000000..c89f445e5 --- /dev/null +++ b/tests/integration/targets/ntnx_acps/tasks/create_acps.yml @@ -0,0 +1,187 @@ +--- +- name: Create min ACP + ntnx_acps: + state: present + wait: True + name: MinACP1 + role: + uuid: "{{ acp.role.uuid }}" + register: result + check_mode: true + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.spec.name == 'MinACP1' + fail_msg: " Unable to create Min ACP with check mode " + success_msg: " Min ACP with check mode passed" +########################################################## +- name: Create min ACP + ntnx_acps: + state: present + wait: true + name: MinACP1 + role: + uuid: '{{ acp.role.uuid }}' + check_mode: false + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + - result.response.spec.name == 'MinACP1' + fail_msg: " Unable to create Min ACP " + success_msg: " Min ACP created successfully " + +- set_fact: + todelete: "{{ todelete + [ result.acp_uuid ] }}" +########################################################## +- name: Create ACP with user reference + ntnx_acps: + state: present + name: acp_with_user_reference1 + role: + uuid: "{{ acp.role.uuid }}" + user_uuids: + - "{{ acp.user_uuid }}" + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + - result.response.spec.name == 'acp_with_user_reference1' + - result.response.status.resources.role_reference.uuid == "{{ acp.role.uuid }}" + - result.response.status.resources.user_reference_list.0.uuid == "{{ acp.user_uuid }}" + fail_msg: " Unable to Create ACP with user reference " + success_msg: " ACP with user reference created successfully " + +- set_fact: + todelete: "{{ todelete + [ result.acp_uuid ] }}" +########################################################## +- name: Create ACP with user ad user group reference + ntnx_acps: + state: present + name: acp_with_user_and_user_group_reference1 + role: + uuid: "{{ acp.role.uuid }}" + user_uuids: + - "{{ acp.user_uuid }}" + user_group_uuids: + - "{{ acp.user_group_uuid }}" + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + - result.response.spec.name == 'acp_with_user_and_user_group_reference1' + - result.response.status.resources.role_reference.uuid == "{{ acp.role.uuid }}" + - result.response.status.resources.user_reference_list.0.uuid == "{{ acp.user_uuid }}" + - result.response.status.resources.user_group_reference_list.0.uuid == "{{ acp.user_group_uuid }}" + fail_msg: " Unable to Create ACP with user and user group reference " + success_msg: " ACP with user and user group reference created successfully " + +- set_fact: + todelete: "{{ todelete + [ result.acp_uuid ] }}" +########################################################## +- name: Create ACP with all specfactions + ntnx_acps: + state: present + name: acp_with_all_specfactions1 + role: + uuid: "{{ acp.role.uuid }}" + user_uuids: + - "{{ acp.user_uuid }}" + user_group_uuids: + - "{{ acp.user_group_uuid }}" + filters: + - scope_filter: + - lhs: PROJECT + operator: IN + rhs: + uuid_list: + - "{{ project.uuid }}" + entity_filter: + - lhs: image + operator: IN + rhs: + collection: ALL + - lhs: subnet + operator: IN + rhs: + uuid_list: + - "{{ network.dhcp.uuid }}" + - scope_filter: + - lhs: CATEGORY + operator: IN + rhs: + categories: + Environment: + - "Dev" + entity_filter: + - lhs: vm + operator: IN + rhs: + collection: ALL + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + - result.response.status.resources.role_reference.uuid == "{{ acp.role.uuid }}" + - result.response.status.resources.user_reference_list.0.uuid == "{{ acp.user_uuid }}" + - result.response.status.resources.user_group_reference_list.0.uuid == "{{ acp.user_group_uuid }}" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.0.operator == "IN" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.0.left_hand_side.entity_type == "image" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.0.right_hand_side.collection == "ALL" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.1.operator == "IN" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.1.left_hand_side.entity_type == "subnet" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.1.right_hand_side.uuid_list.0 == "{{ network.dhcp.uuid }}" + - result.response.status.resources.filter_list.context_list.0.scope_filter_expression_list.0.operator == "IN" + - result.response.status.resources.filter_list.context_list.0.scope_filter_expression_list.0.left_hand_side == "PROJECT" + - result.response.status.resources.filter_list.context_list.0.scope_filter_expression_list.0.right_hand_side.uuid_list.0 == "{{ project.uuid }}" + - result.response.status.resources.filter_list.context_list.1.entity_filter_expression_list.0.operator == "IN" + - result.response.status.resources.filter_list.context_list.1.entity_filter_expression_list.0.left_hand_side.entity_type == "vm" + - result.response.status.resources.filter_list.context_list.1.entity_filter_expression_list.0.right_hand_side.collection == "ALL" + - result.response.status.resources.filter_list.context_list.1.scope_filter_expression_list.0.operator == "IN" + - result.response.status.resources.filter_list.context_list.1.scope_filter_expression_list.0.left_hand_side == "CATEGORY" + fail_msg: " Unable to Create ACP all specfactions " + success_msg: " ACP with all specfactions created successfully " + +- set_fact: + todelete: "{{ todelete + [ result.acp_uuid ] }}" +########################################################## +- name: Delete all created acps + ntnx_acps: + state: absent + acp_uuid: "{{ item }}" + register: result + loop: "{{ todelete }}" + ignore_errors: True + +- name: check listing status + assert: + that: + - result.changed is defined + - result.changed == true + - result.msg == "All items completed" + fail_msg: "unable to delete all created acp's" + success_msg: "All acp's deleted succesfully" + +- set_fact: + todelete: [] \ No newline at end of file diff --git a/tests/integration/targets/ntnx_acps/tasks/delete_acp.yml b/tests/integration/targets/ntnx_acps/tasks/delete_acp.yml new file mode 100644 index 000000000..cb5c3d188 --- /dev/null +++ b/tests/integration/targets/ntnx_acps/tasks/delete_acp.yml @@ -0,0 +1,62 @@ +--- +- name: Create ACP with all specfactions + ntnx_acps: + state: present + name: acp_with_all_specfactions1 + role: + uuid: "{{ acp.role.uuid }}" + user_uuids: + - "{{ acp.user_uuid }}" + user_group_uuids: + - "{{ acp.user_group_uuid }}" + filters: + - scope_filter: + - + lhs: PROJECT + operator: IN + rhs: + uuid_list: + - "{{ project.uuid }}" + entity_filter: + - + lhs: ALL + operator: IN + rhs: + collection: ALL + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + - result.response.status.resources.role_reference.uuid == "{{ acp.role.uuid }}" + - result.response.status.resources.user_reference_list.0.uuid == "{{ acp.user_uuid }}" + - result.response.status.resources.user_group_reference_list.0.uuid == "{{ acp.user_group_uuid }}" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.0.operator == "IN" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.0.left_hand_side.entity_type == "ALL" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.0.right_hand_side.collection == "ALL" + - result.response.status.resources.filter_list.context_list.0.scope_filter_expression_list.0.operator == "IN" + - result.response.status.resources.filter_list.context_list.0.scope_filter_expression_list.0.left_hand_side == "PROJECT" + - result.response.status.resources.filter_list.context_list.0.scope_filter_expression_list.0.right_hand_side.uuid_list.0 == "{{ project.uuid }}" + fail_msg: " Unable to Create ACP all specfactions " + success_msg: " ACP with all specfactions created successfully " + + +- name: Delete acp + ntnx_acps: + state: absent + acp_uuid: "{{ result.acp_uuid }}" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status == 'SUCCEEDED' + - result.failed == false + - result.changed == true + fail_msg: " Unable to delete ACP with all specfactions " + success_msg: " ACP has been deleted successfully " diff --git a/tests/integration/targets/ntnx_acps/tasks/main.yml b/tests/integration/targets/ntnx_acps/tasks/main.yml new file mode 100644 index 000000000..b75051612 --- /dev/null +++ b/tests/integration/targets/ntnx_acps/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "create_acps.yml" + - import_tasks: "delete_acp.yml" + - import_tasks: "update_acps.yml" + - import_tasks: "negative_scenarios.yml" diff --git a/tests/integration/targets/ntnx_acps/tasks/negative_scenarios.yml b/tests/integration/targets/ntnx_acps/tasks/negative_scenarios.yml new file mode 100644 index 000000000..10312fc1e --- /dev/null +++ b/tests/integration/targets/ntnx_acps/tasks/negative_scenarios.yml @@ -0,0 +1,61 @@ + - debug: + msg: "Started Negative Creation Cases" + + - name: Unknown role name + ntnx_acps: + state: present + name: MinACP2 + role: + name: "unknown987" + register: result + ignore_errors: true + + - name: Creation Status + assert: + that: + - result.failed==True + - result.msg=="Failed generating acp spec" + success_msg: ' Success: returned error as expected ' + fail_msg: ' Fail ACP created successfully with unknown role name ' +####################################################### + - name: Unknown role uuid + ntnx_acps: + state: present + name: MinACP2 + role: + uuid: 00000000-0000-0000-0000-000000000000 + register: result + ignore_errors: True + - name: Creation Status + assert: + that: + - result.failed==True + - result.status_code==405 + success_msg: ' Success: returned error as expected ' + fail_msg: ' Fail acp created successfully with unknown role uuid ' +####################################################### + - name: Delete acp with unknown uuid + ntnx_acps: + state: absent + acp_uuid: 5 + ignore_errors: True + register: result + - name: Creation Status + assert: + that: + - result.status_code==400 + success_msg: ' Success: returned error as expected ' + fail_msg: ' Fail deleting acp with unknown uuid ' +####################################################### + - name: Delete acp with missing uuid + ntnx_acps: + state: absent + ignore_errors: True + register: result + + - name: Creation Status + assert: + that: + - result.failed==True + success_msg: ' Success: returned error as expected ' + fail_msg: ' Fail deleting acp with missing uuid ' \ No newline at end of file diff --git a/tests/integration/targets/ntnx_acps/tasks/update_acps.yml b/tests/integration/targets/ntnx_acps/tasks/update_acps.yml new file mode 100644 index 000000000..3394936bb --- /dev/null +++ b/tests/integration/targets/ntnx_acps/tasks/update_acps.yml @@ -0,0 +1,105 @@ +--- +- name: Create min ACP + ntnx_acps: + state: present + wait: true + name: integration-test-acp-update1 + role: + uuid: '{{ acp.role.uuid }}' + register: setup_acp + +- name: Creation Status + assert: + that: + - setup_acp.response is defined + - setup_acp.response.status.state == 'COMPLETE' + - setup_acp.response.spec.name == 'integration-test-acp-update1' + - setup_acp.response.status.resources.role_reference.uuid == "{{ acp.role.uuid }}" + fail_msg: "Unable to create ACP for update tests" + success_msg: "ACP created successfully for update tests" + +- set_fact: + todelete: '{{ todelete + [ setup_acp["response"]["metadata"]["uuid"] ] }}' + +############################################# UPDATE TESTS ######################################## + +- name: check idempotency + ntnx_acps: + state: present + acp_uuid: "{{ setup_acp.acp_uuid }}" + name: integration-test-acp-update1 + role: + uuid: '{{ acp.role.uuid }}' + register: result + +- name: check idempotency status + assert: + that: + - result.changed == false + - result.failed == false + - "'Nothing to change' in result.msg" + fail_msg: "Fail: ACP got updated" + success_msg: "Pass: ACP update skipped succesfully due to no changes in spec" + +######################################################################################## + +- name: Update name, desc and filters + ntnx_acps: + state: present + acp_uuid: "{{ setup_acp.acp_uuid }}" + name: integration-test-acp-after-update1 + desc: "description after update" + filters: + - scope_filter: + - + lhs: PROJECT + operator: IN + rhs: + uuid_list: + - "{{ project.uuid }}" + entity_filter: + - + lhs: ALL + operator: IN + rhs: + collection: ALL + register: result + +- name: Update Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + - result.response.status.name == 'integration-test-acp-after-update1' + - result.response.status.description == 'description after update' + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.0.operator == "IN" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.0.left_hand_side.entity_type == "ALL" + - result.response.status.resources.filter_list.context_list.0.entity_filter_expression_list.0.right_hand_side.collection == "ALL" + - result.response.status.resources.filter_list.context_list.0.scope_filter_expression_list.0.operator == "IN" + - result.response.status.resources.filter_list.context_list.0.scope_filter_expression_list.0.left_hand_side == "PROJECT" + - result.response.status.resources.filter_list.context_list.0.scope_filter_expression_list.0.right_hand_side.uuid_list.0 == "{{ project.uuid }}" + fail_msg: "Fail: Unable to update ACP" + success_msg: "Pass: ACP with given update spec updated successfully" + +########################################### Cleanup ################################################### + +- name: cleanup created entities + ntnx_acps: + state: absent + acp_uuid: "{{ item }}" + register: result + loop: "{{ todelete }}" + ignore_errors: True + + +- name: check listing status + assert: + that: + - result.changed is defined + - result.changed == true + - result.msg == "All items completed" + fail_msg: "unable to delete all created acp's" + success_msg: "All acp's deleted succesfully" + +- set_fact: + todelete: [] \ No newline at end of file diff --git a/tests/integration/targets/ntnx_acps_info/aliases b/tests/integration/targets/ntnx_acps_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_acps_info/meta/main.yml b/tests/integration/targets/ntnx_acps_info/meta/main.yml new file mode 100644 index 000000000..23b0fb268 --- /dev/null +++ b/tests/integration/targets/ntnx_acps_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env \ No newline at end of file diff --git a/tests/integration/targets/ntnx_acps_info/tasks/info.yml b/tests/integration/targets/ntnx_acps_info/tasks/info.yml new file mode 100644 index 000000000..e97712416 --- /dev/null +++ b/tests/integration/targets/ntnx_acps_info/tasks/info.yml @@ -0,0 +1,56 @@ +--- +- debug: + msg: "start ntnx_acps_info tests" + +- name: test getting all acp's + ntnx_acps_info: + kind: access_control_policy + length: 1 + offset: 1 + sort_order: "ASCENDING" + sort_attribute: "name" + register: acps + +- name: check listing status + assert: + that: + - acps.response is defined + - acps.changed == false + - acps.failed == false + fail_msg: "Unable to list all acps" + success_msg: "acps listed successfully" +################################################################ + +- name: test getting particular acp using filter + ntnx_acps_info: + filter: + name: "{{ acps.response.entities.0.status.name }}" + register: result + + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0].metadata.uuid == '{{ acps.response.entities.0.metadata.uuid }}' + fail_msg: "Unable to get particular acp using filter" + success_msg: "acp info obtained successfully using filter" + +################################################################# + +- name: test getting particular acp using uuid + ntnx_acps_info: + acp_uuid: '{{ acps.response.entities.0.metadata.uuid }}' + register: result + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.status.name == '{{ acps.response.entities.0.status.name }}' + fail_msg: "Unable to get particular acp using uuid" + success_msg: "acp info obtained successfully using uuid" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_acps_info/tasks/main.yml b/tests/integration/targets/ntnx_acps_info/tasks/main.yml new file mode 100644 index 000000000..3364b30c6 --- /dev/null +++ b/tests/integration/targets/ntnx_acps_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "info.yml" diff --git a/tests/integration/targets/ntnx_address_groups/aliases b/tests/integration/targets/ntnx_address_groups/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_address_groups/meta/main.yml b/tests/integration/targets/ntnx_address_groups/meta/main.yml new file mode 100644 index 000000000..23b0fb268 --- /dev/null +++ b/tests/integration/targets/ntnx_address_groups/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env \ No newline at end of file diff --git a/tests/integration/targets/ntnx_address_groups/tasks/create.yml b/tests/integration/targets/ntnx_address_groups/tasks/create.yml new file mode 100644 index 000000000..b980b26d9 --- /dev/null +++ b/tests/integration/targets/ntnx_address_groups/tasks/create.yml @@ -0,0 +1,97 @@ +--- +- debug: + msg: start ntnx_address_groups create tests + +- name: Create address group + ntnx_address_groups: + state: present + name: test-ansible-group-1 + desc: test-ansible-group-1-desc + subnets: + - network_ip: "10.1.1.0" + network_prefix: 24 + - network_ip: "10.1.2.2" + network_prefix: 32 + register: result + +- name: Creation Status + assert: + that: + - result.response is defined + - result.address_group_uuid is defined + - result.changed == True + - result.response.name == "test-ansible-group-1" + - result.response.description == "test-ansible-group-1-desc" + - result.response.ip_address_block_list[0].ip == "10.1.1.0" + - result.response.ip_address_block_list[1].ip == "10.1.2.2" + - result.response.ip_address_block_list[0].prefix_length == 24 + - result.response.ip_address_block_list[1].prefix_length == 32 + + fail_msg: "Unable to create address group" + success_msg: "Address group created susccessfully" + +- set_fact: + todelete: '{{ result["address_group_uuid"] }}' + +################################################################################################### + +- name: Check if address group with existing name fails or not + ntnx_address_groups: + state: present + name: test-ansible-group-1 + subnets: + - network_ip: "10.1.1.0" + network_prefix: 24 + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.msg == "Address group with given name already exists" + - result.changed == False + + fail_msg: "Was able to create address group with existing address group name" + success_msg: "Address group with existing address group name failed successfully" + +################################################################################################### +- name: Check mode test + check_mode: yes + ntnx_address_groups: + state: present + name: test-ansible-address-group-2 + desc: test-ansible-address-group-2-desc + subnets: + - network_ip: "10.1.1.0" + network_prefix: 24 + - network_ip: "10.1.2.2" + network_prefix: 32 + register: result + +- name: Check mode Status + assert: + that: + - result.response is defined + - result.changed == False + - result.response.name == "test-ansible-address-group-2" + - result.response.description == "test-ansible-address-group-2-desc" + - result.response.ip_address_block_list[0].ip == "10.1.1.0" + - result.response.ip_address_block_list[1].ip == "10.1.2.2" + - result.response.ip_address_block_list[0].prefix_length == 24 + - result.response.ip_address_block_list[1].prefix_length == 32 + + fail_msg: "Unable to use check mode" + success_msg: "Spec generated successfully with check mode" + +################################################################################################### + + +- name: cleanup created entities + ntnx_address_groups: + state: absent + address_group_uuid: "{{ todelete }}" + register: result + ignore_errors: True + +- set_fact: + todelete: [] \ No newline at end of file diff --git a/tests/integration/targets/ntnx_address_groups/tasks/delete.yml b/tests/integration/targets/ntnx_address_groups/tasks/delete.yml new file mode 100644 index 000000000..99d73237a --- /dev/null +++ b/tests/integration/targets/ntnx_address_groups/tasks/delete.yml @@ -0,0 +1,38 @@ +--- +- debug: + msg: start ntnx_address_groups create tests + +- name: Create address group + ntnx_address_groups: + state: present + name: test-ansible-address-group-4 + desc: test-ansible-address-group-4-desc + subnets: + - network_ip: "10.0.1.0" + network_prefix: 24 + register: test_ag + +- name: Creation Status + assert: + that: + - test_ag.response is defined + - test_ag.changed == True + fail_msg: "Unable to create address group" + success_msg: "address group created susccessfully" + +################################################################################################### + +- name: delete address group + ntnx_address_groups: + state: absent + address_group_uuid: "{{ test_ag.address_group_uuid }}" + register: result + +- name: delete Status + assert: + that: + - result.response is defined + - result.changed == True + + fail_msg: "address group delete failed" + success_msg: "address group deleted successfully" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_address_groups/tasks/main.yml b/tests/integration/targets/ntnx_address_groups/tasks/main.yml new file mode 100644 index 000000000..a2c7a07b0 --- /dev/null +++ b/tests/integration/targets/ntnx_address_groups/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "create.yml" + - import_tasks: "update.yml" + - import_tasks: "delete.yml" diff --git a/tests/integration/targets/ntnx_address_groups/tasks/update.yml b/tests/integration/targets/ntnx_address_groups/tasks/update.yml new file mode 100644 index 000000000..479fcd06a --- /dev/null +++ b/tests/integration/targets/ntnx_address_groups/tasks/update.yml @@ -0,0 +1,118 @@ +--- +- debug: + msg: start ntnx_address_groups create tests + +############################################################################################## + +- name: Create address group with + ntnx_address_groups: + state: present + name: test-ansible-address-group-3 + desc: test-ansible-address-group-3-desc + subnets: + - network_ip: "10.1.1.0" + network_prefix: 24 + - network_ip: "10.1.2.1" + network_prefix: 32 + register: test_ag + +- name: Creation Status + assert: + that: + - test_ag.response is defined + - test_ag.changed == True + fail_msg: "Unable to create adress group" + success_msg: "Address group created susccessfully" + + +################################################################################################### + +- name: Update all fields + ntnx_address_groups: + state: present + address_group_uuid: "{{test_ag.address_group_uuid}}" + name: test-ansible-address-group-3-updated + desc: test-ansible-address-group-3-desc-updated + subnets: + - network_ip: "10.1.3.1" + network_prefix: 32 + register: result + +- name: Update status + assert: + that: + - result.response is defined + - result.address_group_uuid is defined + - result.changed == True + - result.response.name == "test-ansible-address-group-3-updated" + - result.response.description == "test-ansible-address-group-3-desc-updated" + - result.response.ip_address_block_list[0].ip == "10.1.3.1" + - result.response.ip_address_block_list[0].prefix_length == 32 + - result.response.ip_address_block_list | length == 1 + + fail_msg: "Unable to update address group" + success_msg: "Address group updated susccessfully" + +################################################################################################### + +- name: Idempotency check + ntnx_address_groups: + state: present + address_group_uuid: "{{test_ag.address_group_uuid}}" + name: test-ansible-address-group-3-updated + desc: test-ansible-address-group-3-desc-updated + subnets: + - network_ip: "10.1.3.1" + network_prefix: 32 + register: result + +- name: idempotency check status + assert: + that: + - result.changed == False + - result.failed == False + - "'Nothing to change' in result.msg" + + fail_msg: "Idempotency check failed" + success_msg: "Idempotency check passed" + +################################################################################################### + +- name: Check mode test + check_mode: yes + ntnx_address_groups: + state: present + address_group_uuid: "{{test_ag.address_group_uuid}}" + name: test-ansible-address-group-3 + desc: test-ansible-address-group-3-desc + subnets: + - network_ip: "10.1.1.0" + network_prefix: 24 + - network_ip: "10.1.2.1" + network_prefix: 32 + register: result + +- name: check mode Status + assert: + that: + - result.response is defined + - result.address_group_uuid is defined + - result.changed == False + - result.response.name == "test-ansible-address-group-3" + - result.response.description == "test-ansible-address-group-3-desc" + - result.response.ip_address_block_list[0].ip == "10.1.1.0" + - result.response.ip_address_block_list[1].ip == "10.1.2.1" + - result.response.ip_address_block_list[0].prefix_length == 24 + - result.response.ip_address_block_list[1].prefix_length == 32 + + fail_msg: "Check mode failed" + success_msg: "Check mode spec generated successfully" + +################################################################################################### + +- name: cleanup created entities + ntnx_address_groups: + state: absent + address_group_uuid: "{{test_ag.address_group_uuid}}" + register: result + ignore_errors: True diff --git a/tests/integration/targets/ntnx_address_groups_info/aliases b/tests/integration/targets/ntnx_address_groups_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_address_groups_info/meta/main.yml b/tests/integration/targets/ntnx_address_groups_info/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_address_groups_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_address_groups_info/tasks/address_groups_info.yml b/tests/integration/targets/ntnx_address_groups_info/tasks/address_groups_info.yml new file mode 100644 index 000000000..ff4963b62 --- /dev/null +++ b/tests/integration/targets/ntnx_address_groups_info/tasks/address_groups_info.yml @@ -0,0 +1,111 @@ +- debug: + msg: start testing ntnx_address_groups_info + +- name: Create address groups for tests + ntnx_address_groups: + name: test-address-groups-info-1 + subnets: + - network_ip: "10.0.2.0" + network_prefix: 24 + register: ag_1 + +- name: Create address groups for tests + ntnx_address_groups: + name: test-address-groups-info-2 + subnets: + - network_ip: "10.0.3.1" + network_prefix: 32 + register: ag_2 + +################################################## + +- name: List all address groups + ntnx_address_groups_info: + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.response.metadata.total_matches > 0 + - result.response.entities | length > 0 + fail_msg: "Unable to list all address groups" + success_msg: " address groups info obtained successfully" + +- set_fact: + test_address_groups_name: "{{result.response.entities.1.address_group.name}}" +- set_fact: + test_address_groups_uuid: "{{result.response.entities.1.uuid}}" + +################################################## + +- name: List address groups using uuid criteria + ntnx_address_groups_info: + address_group_uuid: "{{ test_address_groups_uuid }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.name == "{{ test_address_groups_name }}" + fail_msg: "Unable to list address groups using uuid" + success_msg: "add groups info obtained successfully" + +################################################## + +- name: List address groups using filter criteria + ntnx_address_groups_info: + filter: + name: "{{ test_address_groups_name }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0].address_group.name == "{{ test_address_groups_name }}" + - result.response.metadata.kind == "address_group" + - result.response.metadata.total_matches == 1 + fail_msg: "Unable to list address groups using filter" + success_msg: "address groups info obtained successfully" + +################################################## + +- name: List address groups using length and offset + ntnx_address_groups_info: + length: 1 + offset: 1 + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities | length == 1 + fail_msg: "Unable to list address groups using length and offset" + success_msg: "address groups listed successfully using length and offset" + +################################################## + +- name: delete created address groups for tests + ntnx_address_groups: + state: absent + address_group_uuid: "{{ ag_1.address_group_uuid}}" + ignore_errors: true + +- name: delete created address groups for tests + ntnx_address_groups: + state: absent + address_group_uuid: "{{ ag_2.address_group_uuid}}" + ignore_errors: true diff --git a/tests/integration/targets/ntnx_address_groups_info/tasks/main.yml b/tests/integration/targets/ntnx_address_groups_info/tasks/main.yml new file mode 100644 index 000000000..011a2fd92 --- /dev/null +++ b/tests/integration/targets/ntnx_address_groups_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "address_groups_info.yml" diff --git a/tests/integration/targets/ntnx_categories/aliases b/tests/integration/targets/ntnx_categories/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_categories/meta/main.yml b/tests/integration/targets/ntnx_categories/meta/main.yml new file mode 100644 index 000000000..23b0fb268 --- /dev/null +++ b/tests/integration/targets/ntnx_categories/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env \ No newline at end of file diff --git a/tests/integration/targets/ntnx_categories/tasks/all_operations.yml b/tests/integration/targets/ntnx_categories/tasks/all_operations.yml new file mode 100644 index 000000000..e8b0aa0b0 --- /dev/null +++ b/tests/integration/targets/ntnx_categories/tasks/all_operations.yml @@ -0,0 +1,219 @@ +--- +- debug: + msg: Start testing ntnx_categories + +- set_fact: + first_category: + name: test-catA1 + desc: first test description + update_desc: updated test description + second_category: + name: test-catB1 + values: + - 'value-a' + - 'value-b' + - 'value-c' + +- name: Create only category key with description + ntnx_categories: + state: "present" + name: "{{first_category.name}}" + desc: "{{first_category.desc}}" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.response is defined + - result.changed == true + - result.failed == false + - result.response.category_key.name == "{{first_category.name}}" + - result.response.category_key.description == "{{first_category.desc}}" + - result.response.category_values is not defined + fail_msg: "Unable to Create only category key with description" + success_msg: "Create only category key with description finished successfully" +################# +- name: Add values to existing category key having no values & Update description + ntnx_categories: + state: "present" + name: "{{first_category.name}}" + desc: "{{first_category.update_desc}}" + values: + - "{{values.0}}" + - "{{values.1}}" + register: result + ignore_errors: true + + +- name: Creation Status + assert: + that: + - result.response is defined + - result.changed == true + - result.failed == false + - result.response.category_key.name == "{{first_category.name}}" + - result.response.category_key.description == "{{first_category.update_desc}}" + - result.response.category_values.0.value == "{{values.0}}" + - result.response.category_values.1.value == "{{values.1}}" + fail_msg: "Unable to Add values to existing category key having no values & Update description" + success_msg: "Add values to existing category key having no values & Update description finished successfully" +################# +- name: update existing category with same values + ntnx_categories: + state: "present" + name: "{{first_category.name}}" + desc: "{{first_category.update_desc}}" + values: + - "{{values.0}}" + - "{{values.1}}" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.changed == false + - result.failed == false + - result.msg == "Nothing to update." + fail_msg: "Fail: existing category update with wrong values" + success_msg: "Passed: Nothing to update as expected " + ################# +- name: update existing category by deleting some values + ntnx_categories: + state: "absent" + name: "{{first_category.name}}" + desc: "{{first_category.update_desc}}" + values: + - "{{values.1}}" + register: result + ignore_errors: true + +- name: get modified category + ntnx_categories_info: + name: "{{first_category.name}}" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.changed == false + - result.failed == false + - result.response is defined + - result.response.category_values.entities|length == 1 + - result.response.category_values.entities.0.value == "{{values.0}}" + fail_msg: "Fail: unable to update existing category by deleting some values " + success_msg: "Passed: update existing category by deleting some values finished succesfully" +################# +- name: update existing category by deleting all values + ntnx_categories: + state: "absent" + name: "{{first_category.name}}" + remove_values: true + register: result + ignore_errors: true + +- name: get modified category + ntnx_categories_info: + name: "{{first_category.name}}" + register: result + ignore_errors: true + + +- name: Creation Status + assert: + that: + - result.changed == false + - result.failed == false + - result.response is defined + - result.response.category_values.entities|length == 0 + fail_msg: "Fail: unable to update existing category by deleting all values " + success_msg: "Passed: update existing category by deleting all values finished succesfully" +################# +- name: Delte the category + ntnx_categories: + state: "absent" + name: "{{first_category.name}}" + register: result + ignore_errors: true + +- name: search deleted category + ntnx_categories_info: + name: "{{first_category.name}}" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.changed == false + - result.failed == false + - result.response == {} + fail_msg: "Fail: unable to Delete the category " + success_msg: "Passed: Delete the category finished succesfully" + +################# +- name: Create category key and value together with check_mode + ntnx_categories: + state: "present" + name: "{{second_category.name}}" + desc: test description + values: + - "{{values.0}}" + - "{{values.1}}" + register: result + ignore_errors: true + check_mode: true + +- name: Creation Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.category_key.name == "{{second_category.name}}" + - result.response.category_values.0.value == "{{values.0}}" + - result.response.category_values.1.value == "{{values.1}}" + fail_msg: "Unable to Create category key and value together with check_mode" + success_msg: "Create category key and value together with check_mode finished successfully" + +################# +- name: Create category key and value together + ntnx_categories: + state: "present" + name: "{{second_category.name}}" + desc: test description + values: + - "{{values.0}}" + - "{{values.1}}" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.response is defined + - result.changed == true + - result.failed == false + - result.response.category_key.name == "{{second_category.name}}" + - result.response.category_values.0.value == "{{values.0}}" + - result.response.category_values.1.value == "{{values.1}}" + fail_msg: "Unable to Create category key and value together" + success_msg: "Create category key and value together finished successfully" +################# +- name: delete the category + ntnx_categories: + state: "absent" + name: "{{second_category.name}}" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.response is defined + - result.changed == true + - result.failed == false + fail_msg: "Fail: Unable to delete the category" + success_msg: "Pass : category has been deleted successfully" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_categories/tasks/main.yml b/tests/integration/targets/ntnx_categories/tasks/main.yml new file mode 100644 index 000000000..993f405e8 --- /dev/null +++ b/tests/integration/targets/ntnx_categories/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "all_operations.yml" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_categories_info/aliases b/tests/integration/targets/ntnx_categories_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_categories_info/meta/main.yml b/tests/integration/targets/ntnx_categories_info/meta/main.yml new file mode 100644 index 000000000..23b0fb268 --- /dev/null +++ b/tests/integration/targets/ntnx_categories_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env \ No newline at end of file diff --git a/tests/integration/targets/ntnx_categories_info/tasks/info.yml b/tests/integration/targets/ntnx_categories_info/tasks/info.yml new file mode 100644 index 000000000..3326e548d --- /dev/null +++ b/tests/integration/targets/ntnx_categories_info/tasks/info.yml @@ -0,0 +1,83 @@ +--- +- debug: + msg: Start testing ntnx_categories_info + +- name: test getting all categories + ntnx_categories_info: + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response.entities is defined + - result.changed == false + - result.failed == false + - result.response.metadata.total_matches > 0 + - result.response.metadata.length > 0 + fail_msg: "Unable to list all categories" + success_msg: "categories listed successfully" +##################################################################################################### +- set_fact: + category_name: test-catAA + values: + - 'value-a' + - 'value-b' + - 'value-c' + +- name: Create category key + ntnx_categories: + state: "present" + name: "{{category_name}}" + values: "{{ values }}" + register: result + ignore_errors: true + +- name: test getting the category with filter by it's name + ntnx_categories_info: + filter: + name: "{{category_name}}" + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response.entities|length == 1 + - result.changed == false + - result.failed == false + - result.response.entities.0.name == "{{category_name}}" + fail_msg: "Unable to get particular category with name filter" + success_msg: "category info obtained successfully by name filter" +##################################################################################################### +- name: test getting the category by it's name + ntnx_categories_info: + name: "{{category_name}}" + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.changed == false + - result.failed == false + - result.response.category_key.name == "{{category_name}}" + - result.response.category_values.entities | length == 3 + fail_msg: "Unable to get particular category with it's name" + success_msg: "category info obtained successfully by it's name" +##################################################################################################### +- name: delete the category + ntnx_categories: + state: "absent" + name: "{{category_name}}" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.response is defined + - result.changed == true + - result.failed == false + fail_msg: "Fail: Unable to delete the category" + success_msg: "Pass : category has been deleted successfully" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_categories_info/tasks/main.yml b/tests/integration/targets/ntnx_categories_info/tasks/main.yml new file mode 100644 index 000000000..3364b30c6 --- /dev/null +++ b/tests/integration/targets/ntnx_categories_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "info.yml" diff --git a/tests/integration/targets/ntnx_clusters_info/aliases b/tests/integration/targets/ntnx_clusters_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_clusters_info/meta/main.yml b/tests/integration/targets/ntnx_clusters_info/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_clusters_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_clusters_info/tasks/get_clusters_info.yml b/tests/integration/targets/ntnx_clusters_info/tasks/get_clusters_info.yml new file mode 100644 index 000000000..e605c1037 --- /dev/null +++ b/tests/integration/targets/ntnx_clusters_info/tasks/get_clusters_info.yml @@ -0,0 +1,55 @@ +--- +- debug: + msg: Start testing ntnx_clusters_info + +- name: test getting all clusters + ntnx_clusters_info: + register: clusters + ignore_errors: True + +- name: check listing status + assert: + that: + - clusters.response is defined + - clusters.changed == false + - clusters.failed == false + - clusters.response.entities[0].metadata.uuid is defined + fail_msg: "Unable to list all cluster" + success_msg: "clusters listed successfully" + + +- name: test getting particular cluster using uuid + ntnx_clusters_info: + cluster_uuid: '{{ clusters.response.entities[0].metadata.uuid }}' + register: result + ignore_errors: True + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.changed == false + - result.response.metadata.uuid == "{{ clusters.response.entities[0].metadata.uuid }}" + - result.response.status.state == "COMPLETE" + fail_msg: "Unable to get particular cluster" + success_msg: "custer info obtained successfully" + +- name: List clusters using length, offset, sort order and priority sort attribute + ntnx_clusters_info: + length: 2 + offset: 0 + sort_order: "ASCENDING" + sort_attribute: "name" + register: result + ignore_errors: True + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0].metadata.uuid is defined + fail_msg: "Unable to list all cluster" + success_msg: "clusters listed successfully" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_clusters_info/tasks/main.yml b/tests/integration/targets/ntnx_clusters_info/tasks/main.yml new file mode 100644 index 000000000..9cf0aa472 --- /dev/null +++ b/tests/integration/targets/ntnx_clusters_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "get_clusters_info.yml" diff --git a/tests/integration/targets/ntnx_hosts_info/aliases b/tests/integration/targets/ntnx_hosts_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_hosts_info/meta/main.yml b/tests/integration/targets/ntnx_hosts_info/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_hosts_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_hosts_info/tasks/get_hosts_info.yml b/tests/integration/targets/ntnx_hosts_info/tasks/get_hosts_info.yml new file mode 100644 index 000000000..0f4fed984 --- /dev/null +++ b/tests/integration/targets/ntnx_hosts_info/tasks/get_hosts_info.yml @@ -0,0 +1,55 @@ +--- +- debug: + msg: Start testing ntnx_hosts_info + +- name: test getting all hosts + ntnx_hosts_info: + register: hosts + ignore_errors: True + +- name: check listing status + assert: + that: + - hosts.response is defined + - hosts.failed == false + - hosts.changed == false + - hosts.response.entities[0].metadata.uuid is defined + fail_msg: "Unable to list all hosts" + success_msg: "hosts listed successfully" + + +- name: test getting particular host using uuid + ntnx_hosts_info: + host_uuid: '{{ hosts.response.entities[0].metadata.uuid }}' + register: result + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.changed == false + - result.response.status.state == "COMPLETE" + - result.response.metadata.uuid == "{{ hosts.response.entities[0].metadata.uuid }}" + fail_msg: "Unable to get particular host" + success_msg: "host info obtained successfully" + + +- name: List hosts using length, offset, sort order and name sort attribute + ntnx_hosts_info: + length: 2 + offset: 0 + sort_order: "ASCENDING" + sort_attribute: "name" + register: result + ignore_errors: True + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.changed == false + - result.response.entities[0].metadata.uuid is defined + fail_msg: "Unable to list all host" + success_msg: "hosts listed successfully" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_hosts_info/tasks/main.yml b/tests/integration/targets/ntnx_hosts_info/tasks/main.yml new file mode 100644 index 000000000..fccc9eeda --- /dev/null +++ b/tests/integration/targets/ntnx_hosts_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "get_hosts_info.yml" diff --git a/tests/integration/targets/ntnx_image_placement_policies_info/aliases b/tests/integration/targets/ntnx_image_placement_policies_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_image_placement_policy/aliases b/tests/integration/targets/ntnx_image_placement_policy/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_images/aliases b/tests/integration/targets/ntnx_images/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_images/tasks/create.yml b/tests/integration/targets/ntnx_images/tasks/create.yml index 856d9e86c..0195ebc82 100644 --- a/tests/integration/targets/ntnx_images/tasks/create.yml +++ b/tests/integration/targets/ntnx_images/tasks/create.yml @@ -33,7 +33,7 @@ name: integration-test-image-with-upload desc: "uploaded image during integration test" source_path: "{{ disk_image.dest }}" - image_type: "ISO_IMAGE" + image_type: "DISK_IMAGE" categories: Environment: - "Dev" @@ -55,7 +55,7 @@ that: - result.response is defined - result.response.status.state == 'COMPLETE' - - result.response.status.resources.image_type == "ISO_IMAGE" + - result.response.status.resources.image_type == "DISK_IMAGE" - result.response.metadata.categories_mapping['AppType'] == ['Default'] - result.response.metadata.categories_mapping['Environment'] == ['Dev'] - result.response.status.resources.initial_placement_ref_list[0]['uuid'] == "{{ cluster.uuid }}" diff --git a/tests/integration/targets/ntnx_images_info/aliases b/tests/integration/targets/ntnx_images_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_ova/aliases b/tests/integration/targets/ntnx_ova/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_permissions_info/aliases b/tests/integration/targets/ntnx_permissions_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_permissions_info/meta/main.yml b/tests/integration/targets/ntnx_permissions_info/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_permissions_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_permissions_info/tasks/main.yml b/tests/integration/targets/ntnx_permissions_info/tasks/main.yml new file mode 100644 index 000000000..2280180dd --- /dev/null +++ b/tests/integration/targets/ntnx_permissions_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "permissions_info.yml" diff --git a/tests/integration/targets/ntnx_permissions_info/tasks/permissions_info.yml b/tests/integration/targets/ntnx_permissions_info/tasks/permissions_info.yml new file mode 100644 index 000000000..3da5b968d --- /dev/null +++ b/tests/integration/targets/ntnx_permissions_info/tasks/permissions_info.yml @@ -0,0 +1,82 @@ +- debug: + msg: start testing ntnx_permissions_info +################################################## + +- name: List all permissions + ntnx_permissions_info: + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.response.metadata.total_matches > 0 + - result.response.entities | length > 0 + fail_msg: "Unable to list all permissions" + success_msg: "permissions info obtained successfully" + +- set_fact: + test_permission_name: "{{result.response.entities.1.status.name}}" +- set_fact: + test_permission_uuid: "{{result.response.entities.1.metadata.uuid}}" + +################################################## + +- name: List permission using uuid criteria + ntnx_permissions_info: + permission_uuid: "{{ test_permission_uuid }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.status.name == "{{ test_permission_name }}" + - result.response.metadata.kind == "permission" + fail_msg: "Unable to list permission using uuid" + success_msg: "permission info obtained successfully" + +################################################## + +- name: List permissions using filter criteria + ntnx_permissions_info: + filter: + name: "{{ test_permission_name }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0].status.name == "{{ test_permission_name }}" + - result.response.metadata.kind == "permission" + - result.response.metadata.total_matches == 1 + fail_msg: "Unable to list permissions using filter" + success_msg: "permission info obtained successfully" + +################################################## + +- name: List permissions using length and offset + ntnx_permissions_info: + length: 1 + offset: 1 + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities | length == 1 + fail_msg: "Unable to list permissions using length and offset" + success_msg: "permissions listed successfully using length and offset" +################################################## \ No newline at end of file diff --git a/tests/integration/targets/ntnx_projects/meta/main.yml b/tests/integration/targets/ntnx_projects/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_projects/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_projects/tasks/create_project.yml b/tests/integration/targets/ntnx_projects/tasks/create_project.yml new file mode 100644 index 000000000..f3c3f283c --- /dev/null +++ b/tests/integration/targets/ntnx_projects/tasks/create_project.yml @@ -0,0 +1,142 @@ +- name: + debug: + msg: "Start ntnx_project create tests" + +- name: Create Project with minimal spec + ntnx_projects: + name: "test-ansible-project" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.response is defined + - result.changed == true + - result.response.status.state == 'COMPLETE' + - result.response.status.name == 'test-ansible-project' + fail_msg: "Unable to create project with minimal spec" + success_msg: "Project with minimal spec created successfully" + +- set_fact: + todelete: "{{ todelete + [ result.project_uuid ] }}" + +################################################################# + +- name: Create Project with check mode + check_mode: yes + ntnx_projects: + name: "test-ansible-project-1" + desc: desc-123 + subnets: + - name: "{{ network.dhcp.name }}" + - uuid: "{{ static.uuid }}" + default_subnet: + name: "{{ network.dhcp.name }}" + users: + - "{{ users[0] }}" + - "{{ users[1] }}" + external_user_groups: + - "{{ user_groups[0] }}" + resource_limits: + - resource_type: STORAGE + limit: 2046 + register: result + ignore_errors: true + +- name: Check mode Status + assert: + that: + - result.response is defined + - result.changed == false + - result.response.spec.name == 'test-ansible-project-1' + - result.response.spec.description == 'desc-123' + - result.response.spec.resources.resource_domain.resources[0].limit == 2046 + - result.response.spec.resources.resource_domain.resources[0].resource_type == 'STORAGE' + - result.response.spec.resources.user_reference_list[0].uuid == "{{ users[0] }}" + - result.response.spec.resources.user_reference_list[1].uuid == "{{ users[1] }}" + - result.response.spec.resources.external_user_group_reference_list[0].uuid == "{{ user_groups[0] }}" + - result.response.spec.resources.subnet_reference_list[0].uuid == "{{ network.dhcp.uuid }}" + - result.response.spec.resources.subnet_reference_list[1].uuid == "{{ static.uuid }}" + - result.response.spec.resources.default_subnet_reference.uuid == "{{ network.dhcp.uuid }}" + + fail_msg: "Check mode failed" + success_msg: "Check mode operation output verified successfully" + +################################################################# + +- name: Create Project with all specs + ntnx_projects: + name: "test-ansible-project-1" + desc: desc-123 + clusters: + - "{{ cluster.uuid }}" + subnets: + - name: "{{ network.dhcp.name }}" + - uuid: "{{ static.uuid }}" + default_subnet: + name: "{{ network.dhcp.name }}" + users: + - "{{ users[0] }}" + - "{{ users[1] }}" + external_user_groups: + - "{{ user_groups[0] }}" + resource_limits: + - resource_type: STORAGE + limit: 2046 + register: result + ignore_errors: true + +- set_fact: + subnet1: "{{result.response.status.resources.subnet_reference_list[0].uuid}}" + subnet2: "{{result.response.status.resources.subnet_reference_list[1].uuid}}" + user1: "{{result.response.status.resources.user_reference_list[0].uuid}}" + user2: "{{result.response.status.resources.user_reference_list[1].uuid}}" + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + - result.response.status.name == 'test-ansible-project-1' + - result.response.status.description == 'desc-123' + - result.response.status.resources.resource_domain.resources[0].limit == 2046 + - result.response.status.resources.resource_domain.resources[0].resource_type == 'STORAGE' + - ( "{{user1}}" == "{{ users[0] }}" and "{{user2}}" == "{{ users[1] }}" ) or ( "{{user2}}" == "{{ users[0] }}" and "{{user1}}" == "{{ users[1] }}" ) + - ( "{{subnet1}}" == "{{ network.dhcp.uuid }}" and "{{subnet2}}" == "{{ static.uuid }}" ) or ( "{{subnet2}}" == "{{ network.dhcp.uuid }}" and "{{subnet1}}" == "{{ static.uuid }}" ) + - result.response.status.resources.external_user_group_reference_list[0].uuid == "{{ user_groups[0] }}" + - result.response.status.resources.default_subnet_reference.uuid == "{{ network.dhcp.uuid }}" + - result.response.status.resources.cluster_reference_list[0].uuid == "{{ cluster.uuid }}" + + fail_msg: "Unable to create project with all specifications" + success_msg: "Project with all specifications created successfully" + +- set_fact: + todelete: "{{ todelete + [ result.project_uuid ] }}" + +################################################################# +- name: Create Project with alredy existing project name + ntnx_projects: + name: "{{ project.name }}" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.changed == false + - "'Project with given name already exists' in result.msg" + fail_msg: "Project create didn't failed when existing project name given" + success_msg: "Project create errored out successfully when existing project name given" + +################################################################# +- name: Delete all Created Projects + ntnx_projects: + state: absent + project_uuid: "{{ item }}" + register: result + loop: "{{ todelete }}" + ignore_errors: True + +- set_fact: + todelete: [] \ No newline at end of file diff --git a/tests/integration/targets/ntnx_projects/tasks/delete_project.yml b/tests/integration/targets/ntnx_projects/tasks/delete_project.yml new file mode 100644 index 000000000..e1fc273be --- /dev/null +++ b/tests/integration/targets/ntnx_projects/tasks/delete_project.yml @@ -0,0 +1,33 @@ +- name: + debug: + msg: "Start ntnx_project delete tests" + +- name: Create Project for delete + ntnx_projects: + name: "test-ansible-project-3" + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + fail_msg: "Unable to create project with minimal spec" + success_msg: "Project with minimal spec created successfully" + +- name: Delete created project + ntnx_projects: + state: absent + project_uuid: "{{ result.project_uuid }}" + wait: true + register: result + ignore_errors: True + +- name: Delete Status + assert: + that: + - result.response is defined + - result.response.status == 'SUCCEEDED' + fail_msg: "Unable to create project with minimal spec" + success_msg: "Project with minimal spec created successfully" diff --git a/tests/integration/targets/ntnx_projects/tasks/main.yml b/tests/integration/targets/ntnx_projects/tasks/main.yml new file mode 100644 index 000000000..5bbfb78bd --- /dev/null +++ b/tests/integration/targets/ntnx_projects/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "create_project.yml" + - import_tasks: "delete_project.yml" + - import_tasks: "update_project.yml" diff --git a/tests/integration/targets/ntnx_projects/tasks/update_project.yml b/tests/integration/targets/ntnx_projects/tasks/update_project.yml new file mode 100644 index 000000000..8583536de --- /dev/null +++ b/tests/integration/targets/ntnx_projects/tasks/update_project.yml @@ -0,0 +1,150 @@ +- name: + debug: + msg: "Start ntnx_project update tests" + +- name: Create Project + ntnx_projects: + name: "test-ansible-project-4" + desc: desc-123 + subnets: + - name: "{{ network.dhcp.name }}" + default_subnet: + name: "{{ network.dhcp.name }}" + users: + - "{{ users[0] }}" + resource_limits: + - resource_type: STORAGE + limit: 1024 + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + fail_msg: "Unable to create project" + success_msg: "Project created successfully" + +- set_fact: + todelete: "{{ todelete + [ result.project_uuid ] }}" +################################################################# + +- name: Check check mode for update + check_mode: yes + ntnx_projects: + project_uuid: "{{ result.project_uuid }}" + desc: desc-123-updated + clusters: + - "{{ cluster.uuid }}" + subnets: + - uuid: "{{ static.uuid }}" + default_subnet: + uuid: "{{ static.uuid }}" + users: + - "{{ users[1] }}" + external_user_groups: + - "{{ user_groups[0] }}" + resource_limits: + - resource_type: MEMORY + limit: 2046 + register: result + ignore_errors: true + +- name: Check mode Status + assert: + that: + - result.response is defined + - result.changed == false + - result.response.spec.description == 'desc-123-updated' + - result.response.spec.resources.resource_domain.resources[0].limit == 2046 + - result.response.spec.resources.resource_domain.resources[0].resource_type == 'MEMORY' + - result.response.spec.resources.user_reference_list[0].uuid == "{{ users[1] }}" + - result.response.spec.resources.external_user_group_reference_list[0].uuid == "{{ user_groups[0] }}" + - result.response.spec.resources.subnet_reference_list[0].uuid == "{{ static.uuid }}" + - result.response.spec.resources.default_subnet_reference.uuid == "{{ static.uuid }}" + - result.response.spec.resources.cluster_reference_list[0].uuid == "{{ cluster.uuid }}" + + fail_msg: "Check mode response for update is incorrect" + success_msg: "Check mode response for update verified successfully" + +################################################################# + +- name: Update project + ntnx_projects: + project_uuid: "{{ result.project_uuid }}" + desc: desc-123-updated + clusters: + - "{{ cluster.uuid }}" + subnets: + - uuid: "{{ static.uuid }}" + default_subnet: + uuid: "{{ static.uuid }}" + users: + - "{{ users[1] }}" + external_user_groups: + - "{{ user_groups[0] }}" + resource_limits: + - resource_type: STORAGE + limit: 2046 + register: result + ignore_errors: true + +- name: Update Status + assert: + that: + - result.response is defined + - result.changed == true + - result.response.status.state == 'COMPLETE' + - result.response.status.description == 'desc-123-updated' + - result.response.status.resources.resource_domain.resources[0].limit == 2046 + - result.response.status.resources.resource_domain.resources[0].resource_type == 'STORAGE' + - result.response.status.resources.user_reference_list[0].uuid == "{{ users[1] }}" + - result.response.status.resources.external_user_group_reference_list[0].uuid == "{{ user_groups[0] }}" + - result.response.status.resources.subnet_reference_list[0].uuid == "{{ static.uuid }}" + - result.response.status.resources.default_subnet_reference.uuid == "{{ static.uuid }}" + - result.response.status.resources.cluster_reference_list[0].uuid == "{{ cluster.uuid }}" + + fail_msg: "Project update failed" + success_msg: "Project updated successfully" + +################################################################# + +- name: Idempotency check + ntnx_projects: + project_uuid: "{{ result.project_uuid }}" + desc: desc-123-updated + subnets: + - uuid: "{{ static.uuid }}" + default_subnet: + uuid: "{{ static.uuid }}" + users: + - "{{ users[1] }}" + external_user_groups: + - "{{ user_groups[0] }}" + resource_limits: + - resource_type: STORAGE + limit: 2046 + register: result + ignore_errors: true + +- name: Creation Status + assert: + that: + - result.changed == false + - "'Nothing to update' in result.msg" + fail_msg: "Project update didnt got skipped for update spec same as existing project" + success_msg: "Project got skipped successfully for no change in spec" + +################################################################# + +- name: Delete all Created Projects + ntnx_projects: + state: absent + project_uuid: "{{ item }}" + register: result + loop: "{{ todelete }}" + ignore_errors: True + +- set_fact: + todelete: [] \ No newline at end of file diff --git a/tests/integration/targets/ntnx_projects_info/meta/main.yml b/tests/integration/targets/ntnx_projects_info/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_projects_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_projects_info/tasks/main.yml b/tests/integration/targets/ntnx_projects_info/tasks/main.yml new file mode 100644 index 000000000..63f4b1464 --- /dev/null +++ b/tests/integration/targets/ntnx_projects_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "projects_info.yml" diff --git a/tests/integration/targets/ntnx_projects_info/tasks/projects_info.yml b/tests/integration/targets/ntnx_projects_info/tasks/projects_info.yml new file mode 100644 index 000000000..54883b928 --- /dev/null +++ b/tests/integration/targets/ntnx_projects_info/tasks/projects_info.yml @@ -0,0 +1,113 @@ +- name: + debug: + msg: "Start ntnx_project_info tests" + +- name: Create Project with minimal spec + ntnx_projects: + name: "test-ansible-project-7" + register: project_1 + ignore_errors: true + +- name: Create Project with minimal spec + ntnx_projects: + name: "test-ansible-project-8" + register: project_2 + ignore_errors: true + +- set_fact: + todelete: "{{ todelete + [ project_1.project_uuid ] }}" + +- set_fact: + todelete: "{{ todelete + [ project_2.project_uuid ] }}" + +################################################## + +- name: List project using name filter criteria + ntnx_projects_info: + filter: + name: "test-ansible-project-7" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.response.entities[0].status.name == "test-ansible-project-7" + fail_msg: "Unable to list projects using filter" + success_msg: "Project info obtained successfully" + +################################################## + +- name: List all projects + ntnx_projects_info: + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.response.metadata.total_matches > 2 + fail_msg: "Unable to list all projects" + success_msg: "Project info of all projects obtained successfully" + +################################################## + +- name: List project using project uuid criteria + ntnx_projects_info: + project_uuid: "{{ project_2.project_uuid }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.response.status.name == "{{ project_2.response.status.name }}" + - result.response.metadata.kind == "project" + fail_msg: "Unable to list projects using uuid" + success_msg: "Project info obtained successfully" + +################################################## +- name: List project using length and offset + ntnx_projects_info: + length: 1 + offset: 1 + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + fail_msg: "Unable to list projects using length and offset" + success_msg: "Projects listed successfully" + +################################################## +- name: List projects using ascending name sorting + ntnx_projects_info: + sort_order: "ASCENDING" + sort_attribute: "name" + kind: project + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + fail_msg: "Unable to list projects" + success_msg: "Projects listed successfully" + +################################################################# +- name: Delete all Created Projects + ntnx_projects: + state: absent + project_uuid: "{{ item }}" + register: result + loop: "{{ todelete }}" + ignore_errors: True + +- set_fact: + todelete: [] \ No newline at end of file diff --git a/tests/integration/targets/ntnx_projects_info/vars/main.yml b/tests/integration/targets/ntnx_projects_info/vars/main.yml new file mode 100644 index 000000000..73b314ff7 --- /dev/null +++ b/tests/integration/targets/ntnx_projects_info/vars/main.yml @@ -0,0 +1 @@ +--- \ No newline at end of file diff --git a/tests/integration/targets/ntnx_roles/aliases b/tests/integration/targets/ntnx_roles/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_roles/meta/main.yml b/tests/integration/targets/ntnx_roles/meta/main.yml new file mode 100644 index 000000000..23b0fb268 --- /dev/null +++ b/tests/integration/targets/ntnx_roles/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env \ No newline at end of file diff --git a/tests/integration/targets/ntnx_roles/tasks/create.yml b/tests/integration/targets/ntnx_roles/tasks/create.yml new file mode 100644 index 000000000..4b3721bc7 --- /dev/null +++ b/tests/integration/targets/ntnx_roles/tasks/create.yml @@ -0,0 +1,112 @@ +--- +- debug: + msg: start ntnx_roles create tests + +- name: Get Some permissions for test + ntnx_permissions_info: + length: 3 + register: result + +- set_fact: + test_permission_1_name: "{{ result.response.entities[0].status.name }}" + test_permission_1_uuid: "{{ result.response.entities[0].metadata.uuid }}" + test_permission_2_name: "{{ result.response.entities[1].status.name }}" + test_permission_2_uuid: "{{ result.response.entities[1].metadata.uuid }}" + test_permission_3_name: "{{ result.response.entities[2].status.name }}" + test_permission_3_uuid: "{{ result.response.entities[2].metadata.uuid }}" + +############################################################################################## + +- name: Create roles with permissions + ntnx_roles: + state: present + name: test-ansible-role-1 + desc: test-ansible-role-1-desc + permissions: + - name: "{{ test_permission_1_name }}" + - uuid: "{{ test_permission_2_uuid }}" + wait: true + register: result + +- set_fact: + p1: "{{ result.response.status.resources.permission_reference_list[0].uuid }}" + p2: "{{ result.response.status.resources.permission_reference_list[1].uuid }}" + +- name: Creation Status + assert: + that: + - result.response is defined + - result.role_uuid is defined + - result.response.status.state == 'COMPLETE' + - result.changed == True + - result.response.status.name == "test-ansible-role-1" + - result.response.status.description == "test-ansible-role-1-desc" + - ("{{ p1 }}" == "{{ test_permission_1_uuid }}" and "{{ p2 }}" == "{{ test_permission_2_uuid }}") or ("{{ p2 }}" == "{{ test_permission_1_uuid }}" and "{{ p1 }}" == "{{ test_permission_2_uuid }}") + + fail_msg: "Unable to create roles with certain permissions" + success_msg: "Roles with given permissions created susccessfully" + +- set_fact: + todelete: '{{ result["response"]["metadata"]["uuid"] }}' + +################################################################################################### + +- name: Check if role with existing name fails or not + ntnx_roles: + state: present + name: test-ansible-role-1 + permissions: + - name: "{{ test_permission_1_name }}" + - uuid: "{{ test_permission_2_uuid }}" + wait: true + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.msg == "Role with given name already exists" + - result.changed == False + + fail_msg: "Was able to create role with existing role name" + success_msg: "Roles with duplicate role name failed successfully" + +################################################################################################### +- name: Check mode test + check_mode: yes + ntnx_roles: + state: present + name: test-ansible-role-2 + desc: test-ansible-role-1-desc + permissions: + - name: "{{ test_permission_1_name }}" + - uuid: "{{ test_permission_2_uuid }}" + wait: true + register: result + +- name: Creation Status + assert: + that: + - result.response is defined + - result.changed == False + - result.response.spec.name == "test-ansible-role-2" + - result.response.spec.description == "test-ansible-role-1-desc" + - result.response.spec.resources.permission_reference_list[0]["uuid"] == "{{ test_permission_1_uuid }}" + - result.response.spec.resources.permission_reference_list[1]["uuid"] == "{{ test_permission_2_uuid }}" + + fail_msg: "Unable to use check mode" + success_msg: "Spec generated successfully with checkmode" + +################################################################################################### + + +- name: cleanup created entities + ntnx_roles: + state: absent + role_uuid: "{{ todelete }}" + register: result + ignore_errors: True + + +- set_fact: + todelete: [] \ No newline at end of file diff --git a/tests/integration/targets/ntnx_roles/tasks/delete.yml b/tests/integration/targets/ntnx_roles/tasks/delete.yml new file mode 100644 index 000000000..b2d5a0306 --- /dev/null +++ b/tests/integration/targets/ntnx_roles/tasks/delete.yml @@ -0,0 +1,48 @@ +--- +- debug: + msg: start ntnx_roles create tests + +- name: Get Some permissions for test + ntnx_permissions_info: + length: 3 + register: result + +- set_fact: + test_permission_1_uuid: "{{ result.response.entities[0].metadata.uuid }}" + +############################################################################################## + +- name: Create role with permissions + ntnx_roles: + state: present + name: test-ansible-role-4 + desc: test-ansible-role-4-desc + permissions: + - uuid: "{{ test_permission_1_uuid }}" + wait: true + register: test_role + +- name: Creation Status + assert: + that: + - test_role.response is defined + - test_role.changed == True + fail_msg: "Unable to create roles with certain permissions" + success_msg: "Roles with given permissions created susccessfully" + +################################################################################################### + +- name: delete role + ntnx_roles: + state: absent + role_uuid: "{{ test_role.role_uuid }}" + register: result + +- name: delete Status + assert: + that: + - result.response is defined + - result.changed == True + + fail_msg: "role delete failed" + success_msg: "role deleted successfully" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_roles/tasks/main.yml b/tests/integration/targets/ntnx_roles/tasks/main.yml new file mode 100644 index 000000000..a2c7a07b0 --- /dev/null +++ b/tests/integration/targets/ntnx_roles/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "create.yml" + - import_tasks: "update.yml" + - import_tasks: "delete.yml" diff --git a/tests/integration/targets/ntnx_roles/tasks/update.yml b/tests/integration/targets/ntnx_roles/tasks/update.yml new file mode 100644 index 000000000..e729b6669 --- /dev/null +++ b/tests/integration/targets/ntnx_roles/tasks/update.yml @@ -0,0 +1,125 @@ +--- +- debug: + msg: start ntnx_roles create tests + +- name: Get Some permissions for test + ntnx_permissions_info: + length: 3 + register: result + +- set_fact: + test_permission_1_name: "{{ result.response.entities[0].status.name }}" + test_permission_1_uuid: "{{ result.response.entities[0].metadata.uuid }}" + test_permission_2_name: "{{ result.response.entities[1].status.name }}" + test_permission_2_uuid: "{{ result.response.entities[1].metadata.uuid }}" + test_permission_3_name: "{{ result.response.entities[2].status.name }}" + test_permission_3_uuid: "{{ result.response.entities[2].metadata.uuid }}" + +############################################################################################## + +- name: Create role with permissions + ntnx_roles: + state: present + name: test-ansible-role-2 + desc: test-ansible-role-3-desc + permissions: + - name: "{{ test_permission_1_name }}" + - uuid: "{{ test_permission_2_uuid }}" + wait: true + register: test_role + +- name: Creation Status + assert: + that: + - test_role.response is defined + - test_role.changed == True + fail_msg: "Unable to create roles with certain permissions" + success_msg: "Roles with given permissions created susccessfully" + + +################################################################################################### + +- name: Update all fields + ntnx_roles: + state: present + role_uuid: "{{test_role.role_uuid}}" + name: test-ansible-role-2-updated + desc: test-ansible-role-2-desc-updated + permissions: + - uuid: "{{ test_permission_3_uuid }}" + wait: true + register: result + +- name: Update status + assert: + that: + - result.response is defined + - result.role_uuid is defined + - result.response.status.state == 'COMPLETE' + - result.changed == True + - result.response.status.name == "test-ansible-role-2-updated" + - result.response.status.description == "test-ansible-role-2-desc-updated" + - result.response.status.resources.permission_reference_list[0]["uuid"] == "{{ test_permission_3_uuid }}" + - result.response.status.resources.permission_reference_list | length == 1 + + fail_msg: "Unable to update role" + success_msg: "Roles with given permissions updated susccessfully" + +################################################################################################### + +- name: Idempotency check + ntnx_roles: + state: present + role_uuid: "{{test_role.role_uuid}}" + name: test-ansible-role-2-updated + desc: test-ansible-role-2-desc-updated + permissions: + - uuid: "{{ test_permission_3_uuid }}" + wait: true + register: result + +- name: idempotency check status + assert: + that: + - result.changed == False + - result.failed == False + - "'Nothing to change' in result.msg" + + fail_msg: "Idempotency check failed" + success_msg: "Idempotency check passed" + +################################################################################################### + +- name: Check mode test + check_mode: yes + ntnx_roles: + state: present + role_uuid: "{{test_role.role_uuid}}" + name: test-ansible-role-2 + desc: test-ansible-role-2-desc + permissions: + - uuid: "{{ test_permission_1_uuid }}" + wait: true + register: result + +- name: check mode Status + assert: + that: + - result.response is defined + - result.changed == False + - result.response.spec.name == "test-ansible-role-2" + - result.response.spec.description == "test-ansible-role-2-desc" + - result.response.spec.resources.permission_reference_list[0]["uuid"] == "{{ test_permission_1_uuid }}" + - result.response.spec.resources.permission_reference_list | length == 1 + + fail_msg: "Check mode failed" + success_msg: "Check mode spec generated successfully" + +################################################################################################### + +- name: cleanup created entities + ntnx_roles: + state: absent + role_uuid: "{{ test_role.role_uuid }}" + register: result + ignore_errors: True diff --git a/tests/integration/targets/ntnx_roles_info/aliases b/tests/integration/targets/ntnx_roles_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_roles_info/meta/main.yml b/tests/integration/targets/ntnx_roles_info/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_roles_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_roles_info/tasks/main.yml b/tests/integration/targets/ntnx_roles_info/tasks/main.yml new file mode 100644 index 000000000..99faaf32c --- /dev/null +++ b/tests/integration/targets/ntnx_roles_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "roles_info.yml" diff --git a/tests/integration/targets/ntnx_roles_info/tasks/roles_info.yml b/tests/integration/targets/ntnx_roles_info/tasks/roles_info.yml new file mode 100644 index 000000000..874870b07 --- /dev/null +++ b/tests/integration/targets/ntnx_roles_info/tasks/roles_info.yml @@ -0,0 +1,82 @@ +- debug: + msg: start testing ntnx_roles_info +################################################## + +- name: List all roles + ntnx_roles_info: + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.response.metadata.total_matches > 0 + - result.response.entities | length > 0 + fail_msg: "Unable to list all roles" + success_msg: "roles info obtained successfully" + +- set_fact: + test_role_name: "{{result.response.entities.1.status.name}}" +- set_fact: + test_role_uuid: "{{result.response.entities.1.metadata.uuid}}" + +################################################## + +- name: List role using uuid criteria + ntnx_roles_info: + role_uuid: "{{ test_role_uuid }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.status.name == "{{ test_role_name }}" + - result.response.metadata.kind == "role" + fail_msg: "Unable to list role using uuid" + success_msg: "role info obtained successfully" + +################################################## + +- name: List roles using filter criteria + ntnx_roles_info: + filter: + name: "{{ test_role_name }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0].status.name == "{{ test_role_name }}" + - result.response.metadata.kind == "role" + - result.response.metadata.total_matches == 1 + fail_msg: "Unable to list roles using filter" + success_msg: "role info obtained successfully" + +################################################## + +- name: List roles using length and offset + ntnx_roles_info: + length: 1 + offset: 1 + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities | length == 1 + fail_msg: "Unable to list roles using length and offset" + success_msg: "roles listed successfully using length and offset" +################################################## \ No newline at end of file diff --git a/tests/integration/targets/ntnx_security_rules/aliases b/tests/integration/targets/ntnx_security_rules/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_security_rules/vars/main.yml b/tests/integration/targets/ntnx_security_rules/vars/main.yml deleted file mode 100644 index 579189152..000000000 --- a/tests/integration/targets/ntnx_security_rules/vars/main.yml +++ /dev/null @@ -1 +0,0 @@ - quarantine_rule_uuid: 8c520823-8ce2-4b0c-ba18-d2ec7bbd86bc \ No newline at end of file diff --git a/tests/integration/targets/ntnx_security_rules_info/aliases b/tests/integration/targets/ntnx_security_rules_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_service_groups/aliases b/tests/integration/targets/ntnx_service_groups/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_service_groups/meta/main.yml b/tests/integration/targets/ntnx_service_groups/meta/main.yml new file mode 100644 index 000000000..23b0fb268 --- /dev/null +++ b/tests/integration/targets/ntnx_service_groups/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env \ No newline at end of file diff --git a/tests/integration/targets/ntnx_service_groups/tasks/create.yml b/tests/integration/targets/ntnx_service_groups/tasks/create.yml new file mode 100644 index 000000000..334f2ba1e --- /dev/null +++ b/tests/integration/targets/ntnx_service_groups/tasks/create.yml @@ -0,0 +1,180 @@ +--- +- debug: + msg: Start testing ntnx_service_groups creation + +- name: create tcp service group + ntnx_service_groups: + name: tcp_srvive_group + desc: desc + service_details: + tcp: + - "10-50" + - "60-90" + - "98" + - "99" + register: result + ignore_errors: true + +- name: getting particular service_group using uuid + ntnx_service_groups_info: + service_group_uuid: '{{ result.service_group_uuid }}' + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.response.service_group.service_list[0].protocol == "TCP" + - result.response.service_group.service_list[0].tcp_port_range_list[0].start_port == 10 + - result.response.service_group.service_list[0].tcp_port_range_list[0].end_port == 50 + - result.response.service_group.service_list[0].tcp_port_range_list[1].start_port == 60 + - result.response.service_group.service_list[0].tcp_port_range_list[1].end_port == 90 + - result.response.service_group.service_list[0].tcp_port_range_list[2].start_port == 98 + - result.response.service_group.service_list[0].tcp_port_range_list[2].end_port == 98 + - result.response.service_group.service_list[0].tcp_port_range_list[3].start_port == 99 + - result.response.service_group.service_list[0].tcp_port_range_list[3].end_port == 99 + fail_msg: "Fail: Unable to create tcp service group " + success_msg: "Pass: tcp service group created successfully" + +- set_fact: + todelete: "{{ todelete + [ result.response.uuid ] }}" +################################################################ +- name: create udp service group + ntnx_service_groups: + name: udp_srvive_group + desc: desc + service_details: + udp: + - "10-50" + - "60-90" + - "98" + - "99" + register: result + ignore_errors: true + +- name: getting particular service_group using uuid + ntnx_service_groups_info: + service_group_uuid: '{{ result.service_group_uuid }}' + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.response.service_group.service_list[0].protocol == "UDP" + - result.response.service_group.service_list[0].udp_port_range_list[0].start_port == 10 + - result.response.service_group.service_list[0].udp_port_range_list[0].end_port == 50 + - result.response.service_group.service_list[0].udp_port_range_list[1].start_port == 60 + - result.response.service_group.service_list[0].udp_port_range_list[1].end_port == 90 + - result.response.service_group.service_list[0].udp_port_range_list[2].start_port == 98 + - result.response.service_group.service_list[0].udp_port_range_list[2].end_port == 98 + - result.response.service_group.service_list[0].udp_port_range_list[3].start_port == 99 + - result.response.service_group.service_list[0].udp_port_range_list[3].end_port == 99 + fail_msg: "Fail: Unable to create udp service group " + success_msg: "Pass: udp service group created successfully" + +- set_fact: + todelete: "{{ todelete + [ result.response.uuid ] }}" +################################################################ +- name: create icmp with service group + ntnx_service_groups: + name: icmp_srvive_group + desc: desc + service_details: + icmp: + - code: 10 + - type: 1 + - type: 2 + code: 3 + register: result + ignore_errors: true + +- name: getting particular service_group using uuid + ntnx_service_groups_info: + service_group_uuid: '{{ result.service_group_uuid }}' + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.response.service_group.service_list[0].protocol == "ICMP" + - result.response.service_group.service_list[0].icmp_type_code_list[0].code == 10 + - result.response.service_group.service_list[0].icmp_type_code_list[1].type == 1 + - result.response.service_group.service_list[0].icmp_type_code_list[2].code == 3 + - result.response.service_group.service_list[0].icmp_type_code_list[2].type == 2 + fail_msg: "Fail: Unable to create icmp service group " + success_msg: "Pass: icmp service group created successfully" + +- set_fact: + todelete: "{{ todelete + [ result.response.uuid ] }}" +################################################################ +- name: create service group with tcp and udp and icmp + ntnx_service_groups: + name: app_srvive_group + desc: desc + service_details: + tcp: + - "*" + udp: + - "10-50" + - "60-90" + - "99" + any_icmp: True + register: result + ignore_errors: true + +- name: getting particular service_group using uuid + ntnx_service_groups_info: + service_group_uuid: '{{ result.service_group_uuid }}' + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.response.service_group.service_list[0].protocol == "TCP" + - result.response.service_group.service_list[0].tcp_port_range_list[0].start_port == 0 + - result.response.service_group.service_list[0].tcp_port_range_list[0].end_port == 65535 + - result.response.service_group.service_list[1].protocol == "UDP" + - result.response.service_group.service_list[1].udp_port_range_list[0].start_port == 10 + - result.response.service_group.service_list[1].udp_port_range_list[0].end_port == 50 + - result.response.service_group.service_list[1].udp_port_range_list[1].start_port == 60 + - result.response.service_group.service_list[1].udp_port_range_list[1].end_port == 90 + - result.response.service_group.service_list[1].udp_port_range_list[2].start_port == 99 + - result.response.service_group.service_list[1].udp_port_range_list[2].end_port == 99 + - result.response.service_group.service_list[2].protocol == "ICMP" + - result.response.service_group.service_list[2].icmp_type_code_list == [] + fail_msg: "Fail: Unable to create tcp service group " + success_msg: "Pass: tcp service group created successfully" + +- set_fact: + todelete: "{{ todelete + [ result.response.uuid ] }}" +################################################################ +- name: Delete all created service groups + ntnx_service_groups: + state: absent + service_group_uuid: "{{ item }}" + register: result + loop: "{{ todelete }}" + ignore_errors: True + +- name: check listing status + assert: + that: + - result.changed is defined + - result.changed == true + - result.msg == "All items completed" + fail_msg: "unable to delete all created service groups" + success_msg: "All service groups deleted succesfully" + +- set_fact: + todelete: [] \ No newline at end of file diff --git a/tests/integration/targets/ntnx_service_groups/tasks/main.yml b/tests/integration/targets/ntnx_service_groups/tasks/main.yml new file mode 100644 index 000000000..6b8a36e1f --- /dev/null +++ b/tests/integration/targets/ntnx_service_groups/tasks/main.yml @@ -0,0 +1,10 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "create.yml" + - import_tasks: "update.yml" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_service_groups/tasks/update.yml b/tests/integration/targets/ntnx_service_groups/tasks/update.yml new file mode 100644 index 000000000..8378c0f60 --- /dev/null +++ b/tests/integration/targets/ntnx_service_groups/tasks/update.yml @@ -0,0 +1,106 @@ +--- + +- name: create tcp service group + ntnx_service_groups: + name: tcp_srvive_group + desc: desc + service_details: + tcp: + - "10-50" + udp: + - "10-50" + icmp: + - code: 10 + register: service_group + ignore_errors: true + +- name: check listing status + assert: + that: + - service_group.response is defined + - service_group.failed == false + - service_group.changed == true + - service_group.response.kind == "service_group" + - service_group.service_group_uuid is defined + fail_msg: "Fail: Unable to create tcp service group " + success_msg: "Pass: tcp service group created successfully" + +- set_fact: + todelete: "{{ todelete + [ service_group.service_group_uuid ] }}" +################################################################ +- name: update tcp service group name and description and other protocols + ntnx_service_groups: + service_group_uuid: "{{service_group.service_group_uuid}}" + name: updated_name + desc: updated_desc + service_details: + tcp: + - "60-90" + icmp: + - type: 2 + code: 3 + register: result + ignore_errors: true + +- name: getting particular service_group using uuid + ntnx_service_groups_info: + service_group_uuid: '{{ result.service_group_uuid }}' + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.changed == false + - result.response.service_group.name == "updated_name" + - result.response.service_group.description == "updated_desc" + - result.response.service_group.service_list[0].protocol == "TCP" + - result.response.service_group.service_list[0].tcp_port_range_list[0].start_port == 60 + - result.response.service_group.service_list[0].tcp_port_range_list[0].end_port == 90 + - result.response.service_group.service_list[1].protocol == "ICMP" + - result.response.service_group.service_list[1].icmp_type_code_list[0].code == 3 + - result.response.service_group.service_list[1].icmp_type_code_list[0].type == 2 + fail_msg: "Fail: Unable to update tcp service group " + success_msg: "Pass: tcp service group update successfully" +################################################################ +- name: update tcp service group with same values + ntnx_service_groups: + service_group_uuid: "{{service_group.service_group_uuid}}" + name: updated_name + desc: updated_desc + service_details: + tcp: + - "60-90" + icmp: + - type: 2 + code: 3 + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.changed == false + - result.failed == false + - result.msg == "Nothing to change. Refer docs to check for fields which can be updated" + fail_msg: "Fail service group updated with same values" + success_msg: "Pass : return as expected " +################################################################ +- name: Delete all created service groups + ntnx_service_groups: + state: absent + service_group_uuid: "{{ item }}" + register: result + loop: "{{ todelete }}" + ignore_errors: True + +- name: check listing status + assert: + that: + - result.changed is defined + - result.changed == true + - result.msg == "All items completed" + fail_msg: "unable to delete all created service groups" + success_msg: "All service groups deleted succesfully" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_service_groups_info/aliases b/tests/integration/targets/ntnx_service_groups_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_service_groups_info/meta/main.yml b/tests/integration/targets/ntnx_service_groups_info/meta/main.yml new file mode 100644 index 000000000..23b0fb268 --- /dev/null +++ b/tests/integration/targets/ntnx_service_groups_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env \ No newline at end of file diff --git a/tests/integration/targets/ntnx_service_groups_info/tasks/info.yml b/tests/integration/targets/ntnx_service_groups_info/tasks/info.yml new file mode 100644 index 000000000..f59db2c01 --- /dev/null +++ b/tests/integration/targets/ntnx_service_groups_info/tasks/info.yml @@ -0,0 +1,74 @@ +--- +- debug: + msg: "start ntnx_service_groups_info tests" + +- name: test getting all service groups + ntnx_service_groups_info: + register: service_groups + ignore_errors: true + +- name: check listing status + assert: + that: + - service_groups.response is defined + - service_groups.changed == false + - service_groups.failed == false + - service_groups.response.entities is defined + - service_groups.response.metadata.kind == "service_group" + fail_msg: "Unable to list all service groups" + success_msg: "service groups listed successfully" +################################################################ +- name: List service_group using length, offset, sort order and name sort attribute + ntnx_service_groups_info: + length: 1 + offset: 1 + sort_order: "ASCENDING" + sort_attribute: "name" + register: result + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities is defined + - result.response.metadata.kind == "service_group" + fail_msg: "Unable to list all service groups using length, offset, sort order and name sort attribute" + success_msg: "service groups listed successfully using length, offset, sort order and name sort attribute" +################################################################ +- name: test getting particular service_group using filter + ntnx_service_groups_info: + filter: + name: "{{ service_groups.response.entities[0].service_group.name }}" + kind: service_group + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0] is defined + - result.response.metadata.kind == "service_group" + - result.response.entities[0].uuid == "{{ service_groups.response.entities[0].uuid }}" + fail_msg: "Unable to get particular service_group" + success_msg: "service_group info obtained successfully" +################################################################ +- name: test getting particular service_group using uuid + ntnx_service_groups_info: + service_group_uuid: '{{ result.response.entities[0].uuid }}' + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.service_group.name == "{{ service_groups.response.entities[0].service_group.name }}" + fail_msg: "Unable to get particular service_group" + success_msg: "service_group info obtained successfully" diff --git a/tests/integration/targets/ntnx_service_groups_info/tasks/main.yml b/tests/integration/targets/ntnx_service_groups_info/tasks/main.yml new file mode 100644 index 000000000..3364b30c6 --- /dev/null +++ b/tests/integration/targets/ntnx_service_groups_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "info.yml" diff --git a/tests/integration/targets/ntnx_static_routes/tasks/create.yml b/tests/integration/targets/ntnx_static_routes/tasks/create.yml index 5d3bbfb65..304ebce6f 100644 --- a/tests/integration/targets/ntnx_static_routes/tasks/create.yml +++ b/tests/integration/targets/ntnx_static_routes/tasks/create.yml @@ -17,8 +17,13 @@ next_hop: external_subnet_ref: uuid: "{{ external_nat_subnet.uuid }}" + wait: True register: result +- set_fact: + d1: "{{ result.response.status.resources.static_routes_list[0].destination }}" + d2: "{{ result.response.status.resources.static_routes_list[1].destination }}" + - name: Update static routes list Status assert: that: @@ -26,10 +31,9 @@ - result.response.status.state == 'COMPLETE' - result.changed == true - result.response.status.resources.static_routes_list[0]["is_active"] == true - - result.response.status.resources.static_routes_list[0]["destination"] == "10.2.2.0/24" + - ("{{d1}}" == "10.2.2.0/24" and "{{d2}}" == "10.2.3.0/24") or ("{{d2}}" == "10.2.2.0/24" and "{{d1}}" == "10.2.3.0/24") - result.response.status.resources.static_routes_list[0]["nexthop"]["external_subnet_reference"]["name"] == "{{ external_nat_subnet.name }}" - result.response.status.resources.static_routes_list[1]["is_active"] == true - - result.response.status.resources.static_routes_list[1]["destination"] == "10.2.3.0/24" - result.response.status.resources.static_routes_list[1]["nexthop"]["external_subnet_reference"]["name"] == "{{ external_nat_subnet.name }}" - result.response.status.resources.default_route["is_active"] == true - result.response.status.resources.default_route["destination"] == "0.0.0.0/0" diff --git a/tests/integration/targets/ntnx_static_routes_info/tasks/info.yml b/tests/integration/targets/ntnx_static_routes_info/tasks/info.yml index 8eda760ab..1bcd6736c 100644 --- a/tests/integration/targets/ntnx_static_routes_info/tasks/info.yml +++ b/tests/integration/targets/ntnx_static_routes_info/tasks/info.yml @@ -35,16 +35,20 @@ vpc_uuid: "{{ vpc.uuid }}" register: result + +- set_fact: + d1: "{{ result.response.status.resources.static_routes_list[0].destination }}" + d2: "{{ result.response.status.resources.static_routes_list[1].destination }}" + - name: check info module response assert: that: - result.response is defined - result.changed == false - - result.response.status.resources.static_routes_list[0]["is_active"] == true - - result.response.status.resources.static_routes_list[0]["destination"] == "10.2.2.0/24" + - result.response.status.resources.static_routes_list[0]["is_active"] == true + - ("{{d1}}" == "10.2.2.0/24" and "{{d2}}" == "10.2.3.0/24") or ("{{d2}}" == "10.2.2.0/24" and "{{d1}}" == "10.2.3.0/24") - result.response.status.resources.static_routes_list[0]["nexthop"]["external_subnet_reference"]["name"] == "{{ external_nat_subnet.name }}" - result.response.status.resources.static_routes_list[1]["is_active"] == true - - result.response.status.resources.static_routes_list[1]["destination"] == "10.2.3.0/24" - result.response.status.resources.static_routes_list[1]["nexthop"]["external_subnet_reference"]["name"] == "{{ external_nat_subnet.name }}" - result.response.status.resources.default_route["is_active"] == true - result.response.status.resources.default_route["destination"] == "0.0.0.0/0" diff --git a/tests/integration/targets/ntnx_user_groups/aliases b/tests/integration/targets/ntnx_user_groups/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_user_groups/meta/main.yml b/tests/integration/targets/ntnx_user_groups/meta/main.yml new file mode 100644 index 000000000..23b0fb268 --- /dev/null +++ b/tests/integration/targets/ntnx_user_groups/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env \ No newline at end of file diff --git a/tests/integration/targets/ntnx_user_groups/tasks/create.yml b/tests/integration/targets/ntnx_user_groups/tasks/create.yml new file mode 100644 index 000000000..27ab2beff --- /dev/null +++ b/tests/integration/targets/ntnx_user_groups/tasks/create.yml @@ -0,0 +1,82 @@ +--- +- debug: + msg: start ntnx_user_groups create tests + +- name: create user group + ntnx_user_groups: + distinguished_name: "{{distinguished_name}}" + project: + uuid: "{{project.uuid}}" + categories: + Environment: + - "Dev" + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.changed == true + - result.response.status.state == "COMPLETE" + - result.user_group_uuid is defined + - result.response.metadata.project_reference.uuid == "{{project.uuid}}" + - result.response.status.resources.directory_service_user_group.distinguished_name == "{{distinguished_name}}" + fail_msg: "Unable to create user group " + success_msg: "user group created successfully" + +- name: delete user group + ntnx_user_groups: + state: absent + user_group_uuid: "{{result.user_group_uuid}}" + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == false + - result.changed == true + - result.response.status == "SUCCEEDED" or result.response.status.state == "DELETE_PENDING" + fail_msg: "Unable to delete user group " + success_msg: "user group deletd successfully" + + +#- name: create user group with idp +# ntnx_user_groups: +# idp: +# idp_uuid: "{{identity_provider_uuid}}" +# group_name: test_group_987 +# register: result +# ignore_errors: true +# +#- name: check listing status +# assert: +# that: +# - result.response is defined +# - result.failed == false +# - result.changed == true +# - result.response.status.state == "COMPLETE" +# - result.user_group_uuid is defined +# - result.response.status.resources.display_name == "test_group_987" +# fail_msg: "Unable to create user group with idp " +# success_msg: "user group with idp created successfully" + +#- name: delete user group +# ntnx_user_groups: +# state: absent +# user_group_uuid: "{{result.user_group_uuid}}" +# register: result +# ignore_errors: true +# +#- name: check listing status +# assert: +# that: +# - result.response is defined +# - result.failed == false +# - result.changed == true +# - result.response.status == "SUCCEEDED" +# fail_msg: "Unable to delete user group with idp " +# success_msg: "user group with idp deleted successfully" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_user_groups/tasks/main.yml b/tests/integration/targets/ntnx_user_groups/tasks/main.yml new file mode 100644 index 000000000..b19cfc1ec --- /dev/null +++ b/tests/integration/targets/ntnx_user_groups/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "create.yml" diff --git a/tests/integration/targets/ntnx_user_groups_info/aliases b/tests/integration/targets/ntnx_user_groups_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_user_groups_info/meta/main.yml b/tests/integration/targets/ntnx_user_groups_info/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_user_groups_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_user_groups_info/tasks/info.yml b/tests/integration/targets/ntnx_user_groups_info/tasks/info.yml new file mode 100644 index 000000000..a4996ab94 --- /dev/null +++ b/tests/integration/targets/ntnx_user_groups_info/tasks/info.yml @@ -0,0 +1,78 @@ +--- +- debug: + msg: start ntnx_user_groups_info tests + +- name: test getting all user groups + ntnx_user_groups_info: + register: user_groups + ignore_errors: true + +- name: check listing status + assert: + that: + - user_groups.response is defined + - user_groups.changed == false + - user_groups.failed == false + - user_groups.response.entities is defined + - user_groups.response.metadata.total_matches > 0 + fail_msg: "Unable to list all user groups" + success_msg: "user groups listed successfully" +################################################################ +- name: List user groups using length, offset, sort order and sort attribute + ntnx_user_groups_info: + length: 2 + offset: 1 + sort_order: "DESCENDING" + sort_attribute: "group_name" + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities is defined + - result.response.metadata.total_matches > 0 + fail_msg: "Unable to list all user groups" + success_msg: "user groups listed successfully" + +################################################################# + +- name: test getting particular user groups using filter + ntnx_user_groups_info: + filter: + group_name: "{{ user_groups.response.entities[0].status.resources.display_name }}" + register: result + ignore_errors: True + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0].status.state == "COMPLETE" + - result.response.entities[0].metadata.uuid == user_groups.response.entities[0].metadata.uuid + fail_msg: "Unable to get particular user groups using filter" + success_msg: "user groups info obtained successfully using filter" + +################################################################## + +- name: test getting particular user group using uuid + ntnx_user_groups_info: + usergroup_uuid: '{{ user_groups.response.entities[0].metadata.uuid }}' + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed ==false + - result.response.status.state == "COMPLETE" + - result.response.status.resources.display_name == user_groups.response.entities[0].status.resources.display_name + fail_msg: "Unable to get particular user group using uuid" + success_msg: "user group info obtained successfully using uuid" diff --git a/tests/integration/targets/ntnx_user_groups_info/tasks/main.yml b/tests/integration/targets/ntnx_user_groups_info/tasks/main.yml new file mode 100644 index 000000000..3364b30c6 --- /dev/null +++ b/tests/integration/targets/ntnx_user_groups_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "info.yml" diff --git a/tests/integration/targets/ntnx_user_groups_info/tasks/user_groups_info.yml b/tests/integration/targets/ntnx_user_groups_info/tasks/user_groups_info.yml new file mode 100644 index 000000000..7f040f27a --- /dev/null +++ b/tests/integration/targets/ntnx_user_groups_info/tasks/user_groups_info.yml @@ -0,0 +1,96 @@ +- debug: + msg: start testing ntnx_user_groups_info +################################################## + +- name: List all user groups + ntnx_user_groups_info: + register: user_groups + ignore_errors: True + +- name: Listing Status + assert: + that: + - user_groups.response is defined + - user_groups.response.metadata.total_matches > 0 + fail_msg: "Unable to list all user groups" + success_msg: "User groups info obtained successfully" + +- set_fact: + test_user_group_name: "{{user_groups.response.entities.1.status.resources.display_name}}" +- set_fact: + test_user_group_uuid: "{{user_groups.response.entities.1.metadata.uuid}}" + +################################################## + +- name: List user_groups using user_group uuid criteria + ntnx_user_groups_info: + user_group_uuid: "{{ test_user_group_uuid }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.status.resources.display_name == "{{ test_user_group_name }}" + - result.response.metadata.kind == "user_group" + fail_msg: "Unable to list user group using uuid" + success_msg: "user group info obtained successfully" + +################################################## + +- name: List user_groups using filter criteria + ntnx_user_groups_info: + filter: + group_name: "{{ test_user_group_name }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0].status.resources.display_name == "{{ test_user_group_name }}" + - result.response.metadata.kind == "user_group" + - result.response.metadata.total_matches == 1 + fail_msg: "Unable to list user groups using filter" + success_msg: "user group info obtained successfully" + +################################################## + +- name: List user groups using length and offset + ntnx_user_groups_info: + length: 1 + offset: 1 + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + fail_msg: "Unable to list user groups using length and offset" + success_msg: "user groups listed successfully using length and offset" +################################################## +- name: List user groups using ascending name sorting + ntnx_user_groups_info: + sort_order: "ASCENDING" + sort_attribute: "group_name" + kind: user_group + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + fail_msg: "Unable to list user groups using ascending name sorting" + success_msg: "user groups listed successfully using ascending name sorting" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_users/aliases b/tests/integration/targets/ntnx_users/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_users/meta/main.yml b/tests/integration/targets/ntnx_users/meta/main.yml new file mode 100644 index 000000000..23b0fb268 --- /dev/null +++ b/tests/integration/targets/ntnx_users/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env \ No newline at end of file diff --git a/tests/integration/targets/ntnx_users/tasks/create.yml b/tests/integration/targets/ntnx_users/tasks/create.yml new file mode 100644 index 000000000..48b8277c3 --- /dev/null +++ b/tests/integration/targets/ntnx_users/tasks/create.yml @@ -0,0 +1,184 @@ +--- +- debug: + msg: "start ntnx_users tests" +################################################## +- name: create local user with check mode + ntnx_users: + principal_name: "{{principal_name}}" + directory_service_uuid: "{{directory_service_uuid}}" + project: + uuid: "{{project.uuid}}" + register: result + ignore_errors: true + check_mode: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.user_uuid == None + - result.response.spec.resources.directory_service_user.directory_service_reference.uuid == "{{directory_service_uuid}}" + fail_msg: "fail: user created whil check mode on" + success_msg: "pass: returned as expected" + +################################################# +- name: create local user + ntnx_users: + principal_name: "{{principal_name}}" + directory_service_uuid: "{{directory_service_uuid}}" + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == true + - result.failed == false + - result.user_uuid is defined + - result.response.status.state == "COMPLETE" + - result.response.status.name == "{{principal_name}}" + - result.response.status.resources.directory_service_user.directory_service_reference.uuid == "{{directory_service_uuid}}" + fail_msg: "fail" + success_msg: "pass" + +- set_fact: + todelete: "{{ todelete + [ result.user_uuid ] }}" +################################################# +- name: Delete created users + ntnx_users: + state: absent + user_uuid: "{{ item }}" + loop: "{{ todelete }}" + register: result + ignore_errors: true +- name: check listing status + assert: + that: + - result.changed == true + - result.msg == "All items completed" + fail_msg: "Fail: unable to delete all users" + success_msg: "Pass: all users deleted succesfully" +- set_fact: + todelete: [] +################################################# +- name: create local user with project and categories + ntnx_users: + principal_name: "{{principal_name}}" + directory_service_uuid: "{{directory_service_uuid}}" + project: + uuid: "{{project.uuid}}" + categories: + Environment: + - "Dev" + AppType: + - "Default" + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == true + - result.failed == false + - result.user_uuid is defined + - result.response.status.state == "COMPLETE" + - result.response.status.name == "{{principal_name}}" + - result.response.status.resources.directory_service_user.directory_service_reference.uuid == "{{directory_service_uuid}}" + fail_msg: "fail" + success_msg: "pass" + +- set_fact: + todelete: "{{ todelete + [ result.user_uuid ] }}" +################################################# +- name: create local user not in the directory_service + ntnx_users: + principal_name: wrong_name + directory_service_uuid: "{{directory_service_uuid}}" + project: + uuid: "{{project.uuid}}" + categories: + Environment: + - "Dev" + AppType: + - "Default" + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.failed == true + - result.changed == false + fail_msg: "Fail: create wrong user" + success_msg: "Pass: Returned as expected" +################################################# +- name: create idp user + ntnx_users: + identity_provider_uuid: "{{identity_provider_uuid}}" + username: testing_user + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == true + - result.failed == false + - result.user_uuid is defined + - result.response.status.state == "COMPLETE" + - result.response.status.name == "testing_user" + fail_msg: "Fail: unable to create idp user" + success_msg: "Pass: idp user created succesfully" + +- set_fact: + todelete: "{{ todelete + [ result.user_uuid ] }}" +################################################# +- name: Delete created users + ntnx_users: + state: absent + user_uuid: "{{ item }}" + loop: "{{ todelete }}" + register: result + ignore_errors: true +- name: check listing status + assert: + that: + - result.changed == true + - result.msg == "All items completed" + fail_msg: "Fail: unable to delete all users" + success_msg: "Pass: all users deleted succesfully" +- set_fact: + todelete: [] + +############# DELETE TEST ############################## + +- name: create local user + ntnx_users: + principal_name: "{{principal_name}}" + directory_service_uuid: "{{directory_service_uuid}}" + project: + uuid: "{{project.uuid}}" + register: result + ignore_errors: true + +- name: Delete created user + ntnx_users: + state: absent + user_uuid: "{{ result.user_uuid }}" + register: result + ignore_errors: true + +- name: check delete status + assert: + that: + - result.changed == true + - result.response is defined + - result.response.status == 'SUCCEEDED' + fail_msg: "Fail: unable to delete users" + success_msg: "Pass: users deleted succesfully" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_users/tasks/main.yml b/tests/integration/targets/ntnx_users/tasks/main.yml new file mode 100644 index 000000000..b19cfc1ec --- /dev/null +++ b/tests/integration/targets/ntnx_users/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "create.yml" diff --git a/tests/integration/targets/ntnx_users_info/aliases b/tests/integration/targets/ntnx_users_info/aliases new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/ntnx_users_info/meta/main.yml b/tests/integration/targets/ntnx_users_info/meta/main.yml new file mode 100644 index 000000000..e4f447d3a --- /dev/null +++ b/tests/integration/targets/ntnx_users_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_env diff --git a/tests/integration/targets/ntnx_users_info/tasks/info.yml b/tests/integration/targets/ntnx_users_info/tasks/info.yml new file mode 100644 index 000000000..46ab6d4a7 --- /dev/null +++ b/tests/integration/targets/ntnx_users_info/tasks/info.yml @@ -0,0 +1,78 @@ +--- +- debug: + msg: "start ntnx_users_info tests" + +- name: test getting all users + ntnx_users_info: + register: users + ignore_errors: true + +- name: check listing status + assert: + that: + - users.response is defined + - users.changed == false + - users.failed == false + - users.response.entities is defined + - users.response.metadata.total_matches > 0 + fail_msg: "Unable to list all users" + success_msg: "Users listed successfully" +################################################################ +- name: List users using length, offset, sort order and sort attribute + ntnx_users_info: + length: 2 + offset: 1 + sort_order: "DESCENDING" + sort_attribute: "username" + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - users.response is defined + - users.changed == false + - users.failed == false + - users.response.entities is defined + - users.response.metadata.total_matches > 0 + fail_msg: "Unable to list all users" + success_msg: "Users listed successfully" + +################################################################ +- name: test getting particular user using filter + ntnx_users_info: + filter: + username: "{{ users.response.entities[1].status.name }}" + register: result + ignore_errors: True + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0].status.state == "COMPLETE" + - result.response.entities[0].metadata.uuid == users.response.entities[1].metadata.uuid + fail_msg: "Unable to get particular user using filter" + success_msg: "User info obtained successfully using filter" + +# ################################################################ + + +- name: test getting particular user using uuid + ntnx_users_info: + user_uuid: '{{ users.response.entities[1].metadata.uuid }}' + register: result + ignore_errors: true + +- name: check listing status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed ==false + - result.response.status.name == users.response.entities[1].status.name + - result.response.status.state == "COMPLETE" + fail_msg: "Unable to get particular user using uuid" + success_msg: "user info obtained successfully using uuid" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_users_info/tasks/main.yml b/tests/integration/targets/ntnx_users_info/tasks/main.yml new file mode 100644 index 000000000..3364b30c6 --- /dev/null +++ b/tests/integration/targets/ntnx_users_info/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: "{{ validate_certs }}" + block: + - import_tasks: "info.yml" diff --git a/tests/integration/targets/ntnx_users_info/tasks/users_info.yml b/tests/integration/targets/ntnx_users_info/tasks/users_info.yml new file mode 100644 index 000000000..389528699 --- /dev/null +++ b/tests/integration/targets/ntnx_users_info/tasks/users_info.yml @@ -0,0 +1,96 @@ +- debug: + msg: start testing ntnx_users_info +################################################## + +- name: List all users + ntnx_users_info: + register: users + ignore_errors: True + +- name: Listing Status + assert: + that: + - users.response is defined + - users.response.metadata.total_matches > 0 + fail_msg: "Unable to list all users" + success_msg: "User info obtained successfully" + +- set_fact: + test_user_name: "{{users.response.entities.2.status.name}}" +- set_fact: + test_user_uuid: "{{users.response.entities.2.metadata.uuid}}" + +################################################## + +- name: List users using user uuid criteria + ntnx_users_info: + user_uuid: "{{ test_user_uuid }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.status.name == "{{ test_user_name }}" + - result.response.metadata.kind == "user" + fail_msg: "Unable to list user using uuid" + success_msg: "user info obtained successfully" + +################################################## + +- name: List users using filter criteria + ntnx_users_info: + filter: + username: "{{ test_user_name }}" + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + - result.response.entities[0].status.name == "{{ test_user_name }}" + - result.response.metadata.kind == "user" + - result.response.metadata.total_matches == 1 + fail_msg: "Unable to list user using filter" + success_msg: "user info obtained successfully" + +################################################## + +- name: List users using length and offset + ntnx_users_info: + length: 1 + offset: 1 + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed == false + fail_msg: "Unable to list users using length and offset" + success_msg: "users listed successfully using length and offset" +################################################## +- name: List users using ascending name sorting + ntnx_users_info: + sort_order: "ASCENDING" + sort_attribute: "name" + kind: user + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.changed == false + - result.failed ==false + fail_msg: "Unable to list users using ascending name sorting" + success_msg: "users listed successfully using ascending name sorting" \ No newline at end of file diff --git a/tests/integration/targets/ntnx_vms_clone/vars/main.yml b/tests/integration/targets/ntnx_vms_clone/vars/main.yml deleted file mode 100644 index 83f47dfce..000000000 --- a/tests/integration/targets/ntnx_vms_clone/vars/main.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -centos: "CentOS-7-cloudinit" -ubuntu: "Ubuntu-20.04.4" -storage_container: - name: SelfServiceContainer - uuid: 701e50d4-dfe5-4294-8c5d-3b7054230b36 -network: - dhcp: - name: vlan.154 - uuid: f1b7a142-ed69-4077-9385-ee34dd6a3532 - static: - ip: 10.30.30.75 -project: - name: integration_test_project - uuid: 4e42ef74-7176-40f1-8e10-f6aa422e896f \ No newline at end of file diff --git a/tests/integration/targets/nutanix_floating_ips_info/tasks/list_floating_ips.yml b/tests/integration/targets/nutanix_floating_ips_info/tasks/list_floating_ips.yml index 7b2d9ef83..43570995d 100644 --- a/tests/integration/targets/nutanix_floating_ips_info/tasks/list_floating_ips.yml +++ b/tests/integration/targets/nutanix_floating_ips_info/tasks/list_floating_ips.yml @@ -1,14 +1,10 @@ - name: List floating_ips using ip filter criteria ntnx_floating_ips_info: filter: - floating_ip: "10." + floating_ip: "10.0.1.2" kind: floating_ip register: result ignore_errors: True - -- name: Show result - debug: - msg: "{{ result.response.entities | map(attribute='status.resources.floating_ip') }}" - name: Listing Status assert: @@ -39,10 +35,6 @@ register: result ignore_errors: True -- name: Show result - debug: - msg: "{{ result.response.entities | map(attribute='status.resources.floating_ip') }}" - - name: Listing Status assert: that: diff --git a/tests/integration/targets/nutanix_pbrs_info/tasks/list_pbrs.yml b/tests/integration/targets/nutanix_pbrs_info/tasks/list_pbrs.yml index 7fe1a1c54..e3948dc4c 100644 --- a/tests/integration/targets/nutanix_pbrs_info/tasks/list_pbrs.yml +++ b/tests/integration/targets/nutanix_pbrs_info/tasks/list_pbrs.yml @@ -34,10 +34,6 @@ register: result ignore_errors: True -- name: Show result - debug: - msg: "{{ result.response.entities | map(attribute='status.name') }}" - - name: Listing Status assert: that: diff --git a/tests/integration/targets/nutanix_subnets/vars/main.yml b/tests/integration/targets/nutanix_subnets/vars/main.yml index b908a8df1..33630dea2 100644 --- a/tests/integration/targets/nutanix_subnets/vars/main.yml +++ b/tests/integration/targets/nutanix_subnets/vars/main.yml @@ -1,4 +1,4 @@ -vlan_subnets_ids: [205, 206, 207, 208, 209, 210] +vlan_subnets_ids: [204, 206, 207, 208, 209, 210] ip_address_management: network_ip: 192.168.0.0 network_prefix: 24 diff --git a/tests/integration/targets/nutanix_subnets_info/tasks/list_subnets.yml b/tests/integration/targets/nutanix_subnets_info/tasks/list_subnets.yml index 79e240394..b6b9890cc 100644 --- a/tests/integration/targets/nutanix_subnets_info/tasks/list_subnets.yml +++ b/tests/integration/targets/nutanix_subnets_info/tasks/list_subnets.yml @@ -5,10 +5,6 @@ register: result ignore_errors: True -- name: Show result - debug: - msg: "{{ result.response.entities | map(attribute='status.name') }}" - - name: Listing Status assert: that: @@ -39,10 +35,6 @@ register: result ignore_errors: True -- name: Show result - debug: - msg: "{{ result.response.entities | map(attribute='status.name') }}" - - name: Listing Status assert: that: diff --git a/tests/integration/targets/nutanix_vms/vars/main.yml b/tests/integration/targets/nutanix_vms/vars/main.yml deleted file mode 100644 index 83f47dfce..000000000 --- a/tests/integration/targets/nutanix_vms/vars/main.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -centos: "CentOS-7-cloudinit" -ubuntu: "Ubuntu-20.04.4" -storage_container: - name: SelfServiceContainer - uuid: 701e50d4-dfe5-4294-8c5d-3b7054230b36 -network: - dhcp: - name: vlan.154 - uuid: f1b7a142-ed69-4077-9385-ee34dd6a3532 - static: - ip: 10.30.30.75 -project: - name: integration_test_project - uuid: 4e42ef74-7176-40f1-8e10-f6aa422e896f \ No newline at end of file diff --git a/tests/integration/targets/nutanix_vms_info/tasks/list_vms.yml b/tests/integration/targets/nutanix_vms_info/tasks/list_vms.yml index 093e9f974..1b758596b 100644 --- a/tests/integration/targets/nutanix_vms_info/tasks/list_vms.yml +++ b/tests/integration/targets/nutanix_vms_info/tasks/list_vms.yml @@ -6,9 +6,6 @@ register: result ignore_errors: True -- name: Show result - debug: - msg: "{{ result.response.entities | map(attribute='spec.name') }}" - name: Listing Status assert: @@ -40,10 +37,6 @@ register: result ignore_errors: True -- name: Show result - debug: - msg: "{{ result.response.entities | map(attribute='spec.name') }}" - - name: Listing Status assert: that: diff --git a/tests/integration/targets/nutanix_vpcs_info/tasks/list_vpcs.yml b/tests/integration/targets/nutanix_vpcs_info/tasks/list_vpcs.yml index 380b78dc0..f21cb3ec2 100644 --- a/tests/integration/targets/nutanix_vpcs_info/tasks/list_vpcs.yml +++ b/tests/integration/targets/nutanix_vpcs_info/tasks/list_vpcs.yml @@ -5,10 +5,6 @@ register: result ignore_errors: True -- name: Show result - debug: - msg: "{{ result.response.entities | map(attribute='status.name') }}" - - name: Listing Status assert: that: @@ -38,10 +34,6 @@ register: result ignore_errors: True -- name: Show result - debug: - msg: "{{ result.response.entities | map(attribute='status.name') }}" - - name: Listing Status assert: that: diff --git a/tests/integration/targets/prepare_env/tasks/prepare_env.yml b/tests/integration/targets/prepare_env/tasks/prepare_env.yml index c2b90cc03..838b17c72 100644 --- a/tests/integration/targets/prepare_env/tasks/prepare_env.yml +++ b/tests/integration/targets/prepare_env/tasks/prepare_env.yml @@ -163,3 +163,12 @@ get_url: url: "{{ disk_image.url }}" dest: "{{ disk_image.dest }}" + + # - name: create address group for network security policy related tests + # ntnx_address_groups: + # state: present + # name: dest + # desc: dest + # subnets: + # - network_ip: "10.1.1.0" + # network_prefix: 24 \ No newline at end of file diff --git a/tests/integration/targets/prepare_env/vars/.gitkeep b/tests/integration/targets/prepare_env/vars/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/targets/prepare_env/vars/main.yml b/tests/integration/targets/prepare_env/vars/main.yml index 534aca61f..e69de29bb 100644 --- a/tests/integration/targets/prepare_env/vars/main.yml +++ b/tests/integration/targets/prepare_env/vars/main.yml @@ -1,38 +0,0 @@ -validate_certs: False -todelete: [] - -disk_image: - url: https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1602.qcow2 - dest: /home/ubuntu/.ansible/collections/ansible_collections/nutanix/ncp/tests/integration/targets/prepare_env/tasks/centosO7-1.qcow2 - checksum: b0e24d81219fe39bfe16d9b10c91e66315333100 - centos: "CentOS-7-cloudinit" - -cluster: - name: auto_cluster_prod_1af28270d50d - uuid: 0005e2f5-ba05-d75a-1fc3-ac1f6b6029c1 - -virtual_switch: - name: vs0 - uuid: 32792030-2db7-4973-920d-36eaf4902c6c -external_nat_subnets: - name: integration_test_Ext-Nat - vlan_id: 103 - gateway_ip_address: 10.44.3.193 - network_prefix: 27 - network_ip: 10.44.3.192 - dhcp: - start_address: 10.44.3.198 - end_address: 10.44.3.207 - static: - start_address: 10.44.3.208 - end_address: 10.44.3.217 - -vpc_name: integration_test_vpc -vm_name: integration_test_vm -static_subnet_name: integration_static_subnet -overlay_subnet: - name: integration_test_overlay_subnet - network_ip: 192.168.1.0 - network_prefix: 24 - gateway_ip: 192.168.1.1 - private_ip: 192.168.1.13 \ No newline at end of file