diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6ab5dd2..f6d016f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,15 @@ Dellemc.Powerstore Change Logs .. contents:: Topics +v2.2.0 +====== + +Minor Changes +------------- + +- Added support for cloning, refreshing, and restoring filesystem. +- Added support for creating and deleting NAS server. +- Info module is enhanced to list discovered appliances. v2.1.0 ====== diff --git a/README.md b/README.md index 2b5c335..2eee705 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,32 @@ # Ansible Modules for Dell Technologies PowerStore - The Ansible Modules for Dell Technologies (Dell) PowerStore allow Data Center and IT administrators to use RedHat Ansible to automate and orchestrate the configuration and management of Dell PowerStore arrays. The capabilities of the Ansible modules are managing volumes, volume groups, vCenters, hosts, host groups, snapshots, snapshot rules, replication rules, replication sessions, protection policies, file systems, NAS servers, SMB shares, user and tree quotas, file system snapshots, NFS exports, Clusters, Networks, Local users, Jobs, Roles, Certificates, Remote systems, security configuration, DNS server, Email notification destination, NTP server, Remote support configuration, Remote support contacts, SMTP configuration, LDAP accounts, LDAP domain configuration and storage containers. It also allows gathering high level info from the array. The options available for each are list, show, create, modify and delete. These tasks can be executed by running simple playbooks written in yaml syntax. The modules are written so that all the operations are idempotent, so making multiple identical requests has the same effect as making a single request. ## Table of contents -* [Code of conduct](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/CODE_OF_CONDUCT.md) -* [Maintainer guide](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/MAINTAINER_GUIDE.md) -* [Committer guide](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/COMMITTER_GUIDE.md) -* [Contributing guide](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/CONTRIBUTING.md) -* [Branching strategy](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/BRANCHING.md) -* [List of adopters](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/ADOPTERS.md) -* [Maintainers](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/MAINTAINERS.md) -* [Support](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/SUPPORT.md) +* [Code of conduct](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/CODE_OF_CONDUCT.md) +* [Maintainer guide](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/MAINTAINER_GUIDE.md) +* [Committer guide](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/COMMITTER_GUIDE.md) +* [Contributing guide](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/CONTRIBUTING.md) +* [Branching strategy](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/BRANCHING.md) +* [List of adopters](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/ADOPTERS.md) +* [Maintainers](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/MAINTAINERS.md) +* [Support](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/SUPPORT.md) * [License](#license) -* [Security](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/SECURITY.md) +* [Security](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/SECURITY.md) * [Prerequisites](#prerequisites) * [List of Ansible modules for Dell PowerStore](#list-of-ansible-modules-for-dell-powerstore) * [Installation and execution of Ansible modules for Dell PowerStore](#installation-and-execution-of-ansible-modules-for-dell-powerstore) * [Maintenance](#maintenance) ## License -The Ansible collection for PowerStore is released and licensed under the GPL-3.0 license. See [LICENSE](https://github.com/dell/ansible-powerstore/blob/2.1.0/LICENSE) for the full terms. Ansible modules and modules utilities that are part of the Ansible collection for PowerStore are released and licensed under the Apache 2.0 license. See [MODULE-LICENSE](https://github.com/dell/ansible-powerstore/blob/2.1.0/MODULE-LICENSE) for the full terms. +The Ansible collection for PowerStore is released and licensed under the GPL-3.0 license. See [LICENSE](https://github.com/dell/ansible-powerstore/blob/2.2.0/LICENSE) for the full terms. Ansible modules and modules utilities that are part of the Ansible collection for PowerStore are released and licensed under the Apache 2.0 license. See [MODULE-LICENSE](https://github.com/dell/ansible-powerstore/blob/2.2.0/MODULE-LICENSE) for the full terms. ## Prerequisites | **Ansible Modules** | **PowerStore Version** | **SDK version** | **Python version** | **Ansible** | |---------------------|-----------------------|-----------------|--------------------|--------------------------| -| v2.1.0 | 3.0.x
3.2.x
3.5.x | 2.0.0 | 3.9.x
3.10.x
3.11.x | 2.13
2.14
2.15 | +| v2.2.0 | 3.0.x
3.2.x
3.5.x | 2.0.0 | 3.9.x
3.10.x
3.11.x | 2.13
2.14
2.15 | * Please follow PyPowerStore installation instructions on [PyPowerStore Documentation](https://github.com/dell/python-powerstore) @@ -36,43 +35,43 @@ The Ansible collection for PowerStore is released and licensed under the GPL-3.0 The modules are written in such a way that all requests are idempotent and hence fault-tolerant. It essentially means that the result of a successfully performed request is independent of the number of times it is executed. ## List of Ansible Modules for Dell PowerStore -* [Volume module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/volume.rst) -* [Volume group module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/volumegroup.rst) -* [Host module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/host.rst) -* [Host group module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/hostgroup.rst) -* [Snapshot module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/snapshot.rst) -* [Snapshot rule module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/snapshotrule.rst) -* [Replication rule module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/replicationrule.rst) -* [Replication session module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/replicationsession.rst) -* [Protection policy module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/protectionpolicy.rst) -* [Info module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/info.rst) -* [File system module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/filesystem.rst) -* [NAS server module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/nasserver.rst) -* [SMB share module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/smbshare.rst) -* [Quota module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/quota.rst) -* [File system snapshot module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/filesystem_snapshot.rst) -* [NFS export module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/nfs.rst) -* [Cluster module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/cluster.rst) -* [Network module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/network.rst) -* [Local user module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/local_user.rst) -* [Role module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/role.rst) -* [Job module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/job.rst) -* [Certificate module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/certificate.rst) -* [Remote system module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/remotesystem.rst) -* [Security config module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/security_config.rst) -* [DNS module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/dns.rst) -* [Email module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/email.rst) -* [NTP module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/ntp.rst) -* [Remote support module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/remote_support.rst) -* [Remote support contact module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/remote_support_contact.rst) -* [SMTP config module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/smtp_config.rst) -* [LDAP Account module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/ldap_account.rst) -* [LDAP Domain module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/ldap_domain.rst) -* [vCenter module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/vcenter.rst) -* [Storage container module](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/modules/storage_container.rst) +* [Volume module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/volume.rst) +* [Volume group module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/volumegroup.rst) +* [Host module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/host.rst) +* [Host group module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/hostgroup.rst) +* [Snapshot module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/snapshot.rst) +* [Snapshot rule module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/snapshotrule.rst) +* [Replication rule module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/replicationrule.rst) +* [Replication session module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/replicationsession.rst) +* [Protection policy module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/protectionpolicy.rst) +* [Info module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/info.rst) +* [File system module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/filesystem.rst) +* [NAS server module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/nasserver.rst) +* [SMB share module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/smbshare.rst) +* [Quota module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/quota.rst) +* [File system snapshot module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/filesystem_snapshot.rst) +* [NFS export module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/nfs.rst) +* [Cluster module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/cluster.rst) +* [Network module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/network.rst) +* [Local user module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/local_user.rst) +* [Role module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/role.rst) +* [Job module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/job.rst) +* [Certificate module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/certificate.rst) +* [Remote system module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/remotesystem.rst) +* [Security config module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/security_config.rst) +* [DNS module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/dns.rst) +* [Email module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/email.rst) +* [NTP module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/ntp.rst) +* [Remote support module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/remote_support.rst) +* [Remote support contact module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/remote_support_contact.rst) +* [SMTP config module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/smtp_config.rst) +* [LDAP Account module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/ldap_account.rst) +* [LDAP Domain module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/ldap_domain.rst) +* [vCenter module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/vcenter.rst) +* [Storage container module](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/modules/storage_container.rst) ## Installation and execution of Ansible modules for Dell PowerStore -The installation and execution steps of Ansible modules for Dell PowerStore can be found [here](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/INSTALLATION.md) +The installation and execution steps of Ansible modules for Dell PowerStore can be found [here](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/INSTALLATION.md) ## Maintenance Ansible Modules for Dell Technologies PowerStore deprecation cycle is aligned with [Ansible](https://docs.ansible.com/ansible/latest/dev_guide/module_lifecycle.html). \ No newline at end of file diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 9fad2ef..5b3e324 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -204,3 +204,10 @@ releases: minor_changes: - Bug fix for initial SMTP configuration in smtp_config module. release_date: '2023-07-31' + 2.2.0: + changes: + minor_changes: + - Added support for cloning, refreshing, and restoring filesystem. + - Added support for creating and deleting NAS server. + - Info module is enhanced to list discovered appliances. + release_date: '2023-09-29' diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 5d1f4f9..94b8083 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -10,7 +10,7 @@ You may obtain a copy of the License at # How to contribute -Become one of the contributors to this project! We thrive to build a welcoming and open community for anyone who wants to use the project or contribute to it. There are just a few small guidelines you need to follow. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/CODE_OF_CONDUCT.md). +Become one of the contributors to this project! We thrive to build a welcoming and open community for anyone who wants to use the project or contribute to it. There are just a few small guidelines you need to follow. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/CODE_OF_CONDUCT.md). ## Table of contents @@ -76,7 +76,7 @@ Triage helps ensure that issues resolve quickly by: If you don't have the knowledge or time to code, consider helping with _issue triage_. The Ansible modules for Dell PowerStore community will thank you for saving them time by spending some of yours. -Read more about the ways you can [Triage issues](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/ISSUE_TRIAGE.md). +Read more about the ways you can [Triage issues](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/ISSUE_TRIAGE.md). ## Your first contribution @@ -89,7 +89,7 @@ When you're ready to contribute, it's time to create a pull request. ## Branching -* [Branching Strategy for Ansible modules for Dell PowerStore](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/BRANCHING.md) +* [Branching Strategy for Ansible modules for Dell PowerStore](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/BRANCHING.md) ## Signing your commits @@ -144,7 +144,7 @@ Make sure that the title for your pull request uses the same format as the subje ### Quality gates for pull requests -GitHub Actions are used to enforce quality gates when a pull request is created or when any commit is made to the pull request. These GitHub Actions enforce our minimum code quality requirement for any code that get checked into the repository. If any of the quality gates fail, it is expected that the contributor will look into the check log, understand the problem and resolve the issue. If help is needed, please feel free to reach out the maintainers of the project for [support](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/SUPPORT.md). +GitHub Actions are used to enforce quality gates when a pull request is created or when any commit is made to the pull request. These GitHub Actions enforce our minimum code quality requirement for any code that get checked into the repository. If any of the quality gates fail, it is expected that the contributor will look into the check log, understand the problem and resolve the issue. If help is needed, please feel free to reach out the maintainers of the project for [support](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/SUPPORT.md). #### Code sanitization diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 2bf42d2..a27b7b6 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -41,7 +41,7 @@ You may obtain a copy of the License at * Download the latest tar build from any of the available distribution channel [Ansible Galaxy](https://galaxy.ansible.com/dellemc/powerstore) /[Automation Hub](https://console.redhat.com/ansible/automation-hub/repo/published/dellemc/powerstore) and use this command to install the collection anywhere in your system: - ansible-galaxy collection install dellemc-powerstore-2.1.0.tar.gz -p + ansible-galaxy collection install dellemc-powerstore-2.2.0.tar.gz -p * Set the environment variable: @@ -68,7 +68,7 @@ You may obtain a copy of the License at ## Ansible modules execution -The Ansible server must be configured with Python library for PowerStore to run the Ansible playbooks. The [Documents](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/) provide information on different Ansible modules along with their functions and syntax. The parameters table in the Product Guide provides information on various parameters which needs to be configured before running the modules. +The Ansible server must be configured with Python library for PowerStore to run the Ansible playbooks. The [Documents](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/) provide information on different Ansible modules along with their functions and syntax. The parameters table in the Product Guide provides information on various parameters which needs to be configured before running the modules. ## SSL certificate validation diff --git a/docs/ISSUE_TRIAGE.md b/docs/ISSUE_TRIAGE.md index 4a07490..1ac9184 100644 --- a/docs/ISSUE_TRIAGE.md +++ b/docs/ISSUE_TRIAGE.md @@ -43,7 +43,7 @@ Should explain what happened, what was expected and how to reproduce it together - Ansible Version: [e.g. 2.14] - Python Version [e.g. 3.11] - - Ansible modules for Dell PowerStore Version: [e.g. 2.1.0] + - Ansible modules for Dell PowerStore Version: [e.g. 2.2.0] - PowerStore SDK version: [e.g. PyPowerStore 1.10.0] - Any other additional information... diff --git a/docs/MAINTAINER_GUIDE.md b/docs/MAINTAINER_GUIDE.md index c430677..a7c038b 100644 --- a/docs/MAINTAINER_GUIDE.md +++ b/docs/MAINTAINER_GUIDE.md @@ -27,7 +27,7 @@ If a candidate is approved, a Maintainer contacts the candidate to invite them t ## Maintainer policies * Lead by example -* Follow the [Code of Conduct](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/CODE_OF_CONDUCT.md) and the guidelines in the [Contributing](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/CONTRIBUTING.md) and [Committer](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/COMMITTER_GUIDE.md) guides +* Follow the [Code of Conduct](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/CODE_OF_CONDUCT.md) and the guidelines in the [Contributing](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/CONTRIBUTING.md) and [Committer](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/COMMITTER_GUIDE.md) guides * Promote a friendly and collaborative environment within our community * Be actively engaged in discussions, answering questions, updating defects, and reviewing pull requests * Criticize code, not people. Ideally, tell the contributor a better way to do what they need. diff --git a/docs/Release Notes.md b/docs/Release Notes.md index 4c2d0c4..ad7c32a 100644 --- a/docs/Release Notes.md +++ b/docs/Release Notes.md @@ -1,6 +1,6 @@ **Ansible Modules for Dell Technologies PowerStore** ========================================= -### Release Notes 2.1.0 +### Release Notes 2.2.0 > © 2022 Dell Inc. or its subsidiaries. All rights reserved. Dell, > and other trademarks are trademarks of Dell Inc. or its @@ -28,7 +28,7 @@ Table 1. Revision history | Revision | Date | Description | |----------|------------|-----------------------------------------------------------| -| 01 | July 2023 | Current release of Ansible Modules for Dell PowerStore 2.1.0 | +| 01 | September 2023 | Current release of Ansible Modules for Dell PowerStore 2.2.0 | Product Description ------------------- @@ -38,17 +38,9 @@ New features & enhancements --------------------------- Along with the previous release deliverables, this release supports these features: -- Volume module is enhanced to support manual appliance selection. -- Info module is enhanced to list storage containers and replication group. -- Added support for replication group in replication session module to perform async vVOL replication. -- Added support for PowerStore Medusa 3.5.x. -- Storage container module supports the following functionalities: - - Create storage container. - - Create storage container destination. - - Delete storage container. - - Delete storage container destination. - - Get details of storage container. - - Modify storage container. +- Added support for cloning, refreshing, and restoring filesystem. +- Added support for creating and deleting NAS server. +- Info module is enhanced to list discovered appliances. Known issues ------------ @@ -65,11 +57,11 @@ Limitations Distribution ---------------- The software package is available for download from the [Ansible Modules -for PowerStore GitHub](https://github.com/dell/ansible-powerstore/tree/2.1.0) page. +for PowerStore GitHub](https://github.com/dell/ansible-powerstore/tree/2.2.0) page. Documentation ------------- -The documentation is available on [Ansible Modules for PowerStore GitHub](https://github.com/dell/ansible-powerstore/tree/2.1.0/docs) +The documentation is available on [Ansible Modules for PowerStore GitHub](https://github.com/dell/ansible-powerstore/tree/2.2.0/docs) page. It includes these: - README - Release Notes (this document) diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 92282f5..8cd026f 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -12,7 +12,7 @@ You may obtain a copy of the License at The Ansible modules for Dell PowerStore repository are inspected for security vulnerabilities via blackduck scans and static code analysis. -In addition to this, there are various security checks that get executed against a branch when a pull request is created/updated. Please refer to [pull request](https://github.com/dell/ansible-powerstore/blob/2.1.0/docs/CONTRIBUTING.md#Pull-requests) for more information. +In addition to this, there are various security checks that get executed against a branch when a pull request is created/updated. Please refer to [pull request](https://github.com/dell/ansible-powerstore/blob/2.2.0/docs/CONTRIBUTING.md#Pull-requests) for more information. ## Reporting a vulnerability diff --git a/docs/modules/cluster.rst b/docs/modules/cluster.rst index 57dc465..9d47ff9 100644 --- a/docs/modules/cluster.rst +++ b/docs/modules/cluster.rst @@ -376,7 +376,7 @@ Examples appliances: - link_local_address: "1.2.x.x" name: "Ansible_cluster" - derive_failure_tolerance_level: "Double" + drive_failure_tolerance_level: "Double" dns_servers: - "1.1.x.x" ntp_servers: @@ -415,7 +415,7 @@ Examples appliances: - link_local_address: "1.2.x.x" name: "Ansible_cluster" - derive_failure_tolerance_level: "Double" + drive_failure_tolerance_level: "Double" dns_servers: - "1.1.x.x" ntp_servers: diff --git a/docs/modules/filesystem.rst b/docs/modules/filesystem.rst index b164582..4ffbf61 100644 --- a/docs/modules/filesystem.rst +++ b/docs/modules/filesystem.rst @@ -14,6 +14,8 @@ Synopsis Supports the provisioning operations on a filesystem such as create, modify, delete and get the details of a filesystem. +Supports clone, refresh and restore operations on a filesystem. + Requirements @@ -205,6 +207,130 @@ Parameters Cannot be modified. + clone_filesystem (optional, dict, None) + The attributes for filesystem clone. + + + name (optional, str, None) + Name of the clone. + + It can only be provided during creation of a filesystem clone. + + + description (optional, str, None) + Description of the clone. + + + access_policy (optional, str, None) + File system security access policies. + + ``Native`` - Native Security. + + ``UNIX`` - UNIX Security. + + ``Windows`` - Windows Security. + + + locking_policy (optional, str, None) + File system locking policies. + + ``Advisory``- No lock checking for NFS and honor SMB lock range only for SMB. + + ``Mandatory``- Honor SMB and NFS lock range. + + + folder_rename_policy (optional, str, None) + File system folder rename policies for the file system with multi-protocol access enabled. + + ``All_Allowed`` - All protocols are allowed to rename directories without any restrictions. + + ``SMB_Forbidden`` - A directory rename from the SMB protocol will be denied if at least one file is opened in the directory or in one of its child directories. + + ``All_Forbidden`` - Any directory rename request will be denied regardless of the protocol used, if at least one file is opened in the directory or in one of its child directories. + + + is_smb_sync_writes_enabled (optional, bool, None) + Indicates whether the synchronous writes option is enabled on the file system. + + + is_smb_no_notify_enabled (optional, bool, None) + Indicates whether notifications of changes to directory file structure are enabled. + + + is_smb_op_locks_enabled (optional, bool, None) + Indicates whether opportunistic file locking is enabled on the file system. + + + is_smb_notify_on_access_enabled (optional, bool, None) + Indicates whether file access notifications are enabled on the file system. + + + is_smb_notify_on_write_enabled (optional, bool, None) + Indicates whether file write notifications are enabled on the file system. + + + smb_notify_on_change_dir_depth (optional, int, None) + Determines the lowest directory level to which the enabled notifications apply. minimum value is ``1``. + + + is_async_MTime_enabled (optional, bool, None) + Indicates whether asynchronous MTIME is enabled on the file system. + + + file_events_publishing_mode (optional, str, None) + State of the event notification services for all file systems of the NAS server. + + ``None`` - File event notifications are disabled for this file system. + + ``SMB_Only`` - SMB notifications are enabled for this file system. + + ``NFS_Only`` - NFS notifications are enabled for this file system. + + ``All`` - SMB and NFS notifications are enabled for this file system. + + + flr_attributes (optional, dict, None) + The attributes for file retention. + + + force_clone (optional, bool, None) + Specifies whether an FLR-C file system should be cloned. + + ``true`` - means cloning an FLR-C file system is allowed. + + ``false`` - means cloning an FLR-C file system is not allowed. and any attempt to do so will return an error. + + + + + snapshot_name (optional, str, None) + The name of the filesystem snapshot. + + Specify either snapshot name or ID (but not both) for restore and refresh operations. + + + snapshot_id (optional, str, None) + The ID of the Snapshot. + + Specify either snapshot name or ID (but not both) for restore and refresh operations. + + + refresh_filesystem (optional, bool, None) + Specifies to refresh filesystem. + + Mandatory only for refresh filesystem. + + + restore_filesystem (optional, bool, None) + Specifies to restore filesystem. + + Mandatory only for restore filesystem. + + + backup_snap_name (optional, str, None) + Name of the backup snap to be created before the restore operation occurs. + + state (True, str, None) Define whether the filesystem should exist or not. @@ -251,6 +377,7 @@ Notes - It is recommended to remove the protection policy before deleting the filesystem. - The *check_mode* is not supported. - The pattern for *minimum_retention*, *default_retention* and *maximum_retention* is (^\d+[DMY])|(^infinite$). + - Filesystem snapshot can be created using filesystem_snapshot module. - The modules present in this collection named as 'dellemc.powerstore' are built to support the Dell PowerStore storage platform. @@ -335,6 +462,54 @@ Examples filesystem_id: "{{result_fs.filesystem_details.id}}" state: "absent" + - name: Clone File System + dellemc.powerstore.filesystem: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + filesystem_name: 'Atest' + nas_server: 'Test_Nas' + clone_filesystem: + name: "Test_ansible" + description: "Test" + access_policy: "UNIX" + locking_policy: "Advisory" + folder_rename_policy: "All_Allowed" + is_smb_sync_writes_enabled: true + is_smb_no_notify_enabled: true + is_smb_op_locks_enabled: true + is_smb_notify_on_access_enabled: true + is_smb_notify_on_write_enabled: true + smb_notify_on_change_dir_depth: 32 + is_async_MTime_enabled: false + file_events_publishing_mode: "All" + flr_attributes: + force_clone: false + state: "present" + + - name: Refresh File System + dellemc.powerstore.filesystem: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + snapshot_name: "Refresh_test" + nas_server: 'Sample_NAS' + refresh_filesystem: true + state: "present" + + - name: Restore File System + dellemc.powerstore.filesystem: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + snapshot_id: "xxx-xxx-xxx" + restore_filesystem: true + backup_snap_name: "Restore_test" + state: "present" + Return Values @@ -344,6 +519,18 @@ changed (always, bool, false) Whether or not the resource has changed. +is_filesystem_cloned (always, bool, false) + Whether or not the clone of filesystem is created. + + +is_filesystem_refreshed (always, bool, false) + Whether or not the filesystem is refreshed. + + +is_filesystem_restored (always, bool, false) + Whether or not the filesystem is restored. + + filesystem_details (When filesystem exists, complex, {'access_policy': 'Native', 'access_policy_l10n': 'Native', 'access_type': None, 'access_type_l10n': None, 'creation_timestamp': None, 'creator_type': None, 'creator_type_l10n': None, 'default_hard_limit': 0, 'default_soft_limit': 0, 'description': None, 'expiration_timestamp': None, 'filesystem_type': 'Primary', 'filesystem_type_l10n': 'Primary', 'folder_rename_policy': 'All_Forbidden', 'folder_rename_policy_l10n': 'All Renames Forbidden', 'grace_period': 604800, 'id': '61e49f3f-9b57-e69b-1038-aa02b52a030f', 'is_async_MTime_enabled': False, 'is_modified': False, 'is_quota_enabled': False, 'is_smb_no_notify_enabled': False, 'is_smb_notify_on_access_enabled': False, 'is_smb_notify_on_write_enabled': False, 'is_smb_op_locks_enabled': True, 'is_smb_sync_writes_enabled': True, 'last_refresh_timestamp': None, 'last_writable_timestamp': None, 'locking_policy': 'Advisory', 'locking_policy_l10n': 'Advisory', 'name': 'sample-filesystem', 'nas_server': {'id': '6026056b-5405-0e36-7697-c285b9fa42b7', 'name': 'ansible_nas_server_2'}, 'parent_id': None, 'protection_policy': None, 'size_total': '214748364800', 'size_used': '1621098496', 'smb_notify_on_change_dir_depth': 512, 'snapshots': {}, 'total_size_with_unit': '200.0 GB', 'used_size_with_unit': '1.51 GB'}) Details of the filesystem. @@ -553,4 +740,5 @@ Authors - Arindam Datta (@dattaarindam) - Trisha Datta (@trisha-dell) +- Pavan Mudunuri(@Pavan-Mudunuri) diff --git a/docs/modules/info.rst b/docs/modules/info.rst index 041af39..16d2fd2 100644 --- a/docs/modules/info.rst +++ b/docs/modules/info.rst @@ -22,7 +22,7 @@ Replication module includes replication rules, replication sessions, replication Virtualization module includes vCenters and virtual volumes. -Configuration module includes cluster nodes, networks, roles, local users, appliances, security configs, certificates, AD/LDAP servers, LDAP accounts, and LDAP domain. +Configuration module includes cluster nodes, networks, roles, local users, appliances, discovered appliances, security configs, certificates, AD/LDAP servers, LDAP accounts, and LDAP domain. It also includes DNS/NTP servers, smtp configs, email destinations, remote support, and remote support contacts. @@ -117,6 +117,8 @@ Parameters Replication groups - ``replication_group``. + Discovered appliances - ``discovered_appliance``. + filters (optional, list, None) A list of filters to support filtered output for storage entities. @@ -184,7 +186,7 @@ Notes ----- .. note:: - - Pagination is not supported for role, local user, security configs, LDAP accounts and LDAP domain. If *all_pages* is passed, it will be ignored. + - Pagination is not supported for role, local user, security configs, LDAP accounts, discovered appliances and LDAP domain. If *all_pages* is passed, it will be ignored. - The *check_mode* is supported. - The modules present in this collection named as 'dellemc.powerstore' are built to support the Dell PowerStore storage platform. @@ -436,7 +438,7 @@ Examples - virtual_volume - replication_group - - name: Get list of storage containers + - name: Get list of storage containers and discovered appliances dellemc.powerstore.info: array_ip: "{{array_ip}}" validate_certs: "{{validate_certs}}" @@ -444,7 +446,7 @@ Examples password: "{{password}}" gather_subset: - storage_container - + - discovered_appliance @@ -468,7 +470,7 @@ ActiveDirectory (When C(ad) is in a given I(gather_subset), list, [{'id': '60866 -Appliance (When C(appliance) is in a given I(gather_subset), list, [{'id': 'A1', 'model': 'PowerStore 1000T', 'name': 'Appliance-WND8977'}]) +Appliance (When C(appliance) is in a given I(gather_subset), list, [{'id': 'A1', 'name': 'Appliance-WND8977', 'service_tag': 'A1', 'express_service_code': 'A1', 'model': 'PowerStore 1000T', 'node_count': 1, 'drive_failure_tolerance_level': 'None', 'is_hyper_converged': False, 'nodes': [], 'ip_pool_addresses': [], 'veth_ports': [], 'virtual_volumes': [], 'maintenance_windows': [], 'fc_ports': [], 'sas_ports': [], 'eth_ports': [], 'eth_be_ports': [], 'software_installed': [], 'hardware': [], 'volumes': []}]) Provides details of all appliances. @@ -480,10 +482,78 @@ Appliance (When C(appliance) is in a given I(gather_subset), list, [{'id': 'A1', Name of the appliance. + service_tag (, str, ) + Dell service tag of the appliance. + + + express_service_code (, str, ) + Express service code. + + model (, str, ) Model type of the PowerStore. + node_count (, int, ) + Number of nodes deployed on an appliance. It was added in version 3.0.0.0. + + + drive_failure_tolerance_level (, str, ) + Drive failure tolerance level. + + + is_hyper_converged (, bool, ) + Whether the appliance is a hyper-converged appliance. It was added in version 3.2.0.0. + + + nodes (, list, ) + Provides details of all nodes. + + + ip_pool_addresses (, list, ) + Provides details of all IP pool addresses. + + + veth_ports (, list, ) + Provides details of all veth ports. + + + virtual_volumes (, list, ) + Provides details of all virtual volumes. + + + maintenance_windows (, list, ) + Provides details of all maintenance windows. + + + fc_ports (, list, ) + Provides details of all FC ports. + + + sas_ports (, list, ) + Provides details of all SAS ports. + + + eth_ports (, list, ) + Provides details of all Ethernet ports. + + + eth_be_ports (, list, ) + Provides details of all eth_be_ports. It was added in version 3.0.0.0. + + + software_installed (, list, ) + Provides details of all software installed. + + + hardware (, list, ) + Provides details of all hardware. + + + volumes (, list, ) + Provides details of all volumes. + + Certificate (When C(certificates) is in a given I(gather_subset), list, [{'id': 'e940144f-393f-4e9c-8f54-9a4d57b38c48'}]) Provides details of all certificates. @@ -507,6 +577,83 @@ Cluster (always, list, [{'id': '0', 'name': 'RT-D1006'}]) +DiscoveredAppliances (When C(discovered_appliance) is in a given I(gather_subset), list, [{'id': 'A1', 'link_local_address': '1.0.2.x', 'service_name': 'Appliance-WND8977', 'service_tag': 'A8977', 'state': 'Unconfigured', 'mode': 'Unified', 'model': 'PowerStore 1000T', 'express_service_code': 'A8977', 'is_local': True, 'management_service_ready': True, 'software_version_compatibility': '3.0.0.0', 'build_version': '3.0.0.0', 'build_id': '3202', 'power_score': 0, 'node_count': 2, 'is_unified_capable': True, 'is_hyper_converged': False}]) + Provides details of all discovered appliances. + + + id (, str, ) + ID of a discovered appliance. The local discovered appliance has the id "0". + + + link_local_address (, str, ) + Link local IPv4 address of the discovered appliance. + + + service_name (, str, ) + Service name of the discovered appliance. + + + service_tag (, str, ) + The Dell service tag. + + + state (, str, ) + Possible unmanaged appliance states. + + + mode (, str, ) + Storage access mode supported by the appliance. + + + model (, str, ) + The model of the appliance. + + + express_service_code (, str, ) + Express service code for the appliance. + + + is_local (, bool, ) + Indicates whether appliance is local or not. + + + management_service_ready (, bool, ) + Indicates whether the management services are ready. + + + software_version_compatibility (, str, ) + Compatibility of the software version on an appliance compared to the software version on the appliance running the request. + + + build_version (, str, ) + Build version of the installed software package release. + + + build_id (, str, ) + Build ID. + + + power_score (, int, ) + Power rating of the appliance. + + + node_count (, int, ) + Number of nodes deployed on an appliance. + + + is_unified_capable (, bool, ) + Indicates whether the appliance is capable of unified configuration. + + + drive_failure_tolerance_level_and_availability (, list, ) + Drive failure tolerance level and availability. + + + is_hyper_converged (, bool, ) + Indicates whether the appliance is a hyper converged or not. It was added in version 3.2.0.0. + + + DNS (When C(dns) is in a given I(gather_subset), list, [{'id': 'DNS1'}]) Provides details of all DNS servers. diff --git a/docs/modules/nasserver.rst b/docs/modules/nasserver.rst index 4fdfead..dc798ac 100644 --- a/docs/modules/nasserver.rst +++ b/docs/modules/nasserver.rst @@ -12,7 +12,7 @@ nasserver -- NAS Server operations for PowerStore Storage system Synopsis -------- -Supports getting the details and modifying the attributes of a NAS server. +Supports getting the details, creating, modifying the attributes of a NAS server and deleting a NAS server. @@ -72,6 +72,16 @@ Parameters Policy can be removed by passing an empty string in the *protection_policy* parameter. + is_username_translation_enabled (optional, bool, None) + Enable the possibility to match a Windows account with an Unix account with different names. + + + is_auto_user_mapping_enabled (optional, bool, None) + To automatically generate the unix user (uid), if the windows user does not have any in the configured Unix Directory Service (UDS). + + In a pure SMB or non multi-protocol environment, this should be set to true. + + state (True, str, None) Define whether the nas server should exist or not. @@ -129,57 +139,82 @@ Examples + - name: Create a NAS Server + dellemc.powerstore.nasserver: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_name: "test-nas-server" + description: "NAS Server test" + current_unix_directory_service: "LDAP" + default_unix_user: "user1" + default_windows_user: "user2" + is_username_translation_enabled: true + is_auto_user_mapping_enabled: true + protection_policy: "ansible_policy" + state: "present" + - name: Get details of NAS Server by name dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_name: "{{nas_server_name}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_name: "{{ nas_server_name }}" state: "present" - name: Get Details of NAS Server by ID dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_id: "{{nas_id}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_id: "{{ nas_id }}" state: "present" - name: Rename NAS Server by Name dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_name: "{{nas_server_name}}" - nas_server_new_name : "{{nas_server_new_name}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_name: "{{ nas_server_name }}" + nas_server_new_name : "{{ nas_server_new_name }}" state: "present" - name: Modify NAS Server attributes by ID dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_id: "{{nas_id}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_id: "{{ nas_id }}" current_unix_directory_service: "LOCAL_FILES" - current_node: "{{cur_node_n1}}" - preferred_node: "{{prefered_node}}" + current_node: "{{ cur_node_n1 }}" + preferred_node: "{{ prefered_node }}" protection_policy: "protection_policy_1" state: "present" - name: Remove protection policy dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_id: "{{nas_id}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_id: "{{ nas_id }}" protection_policy: "" state: "present" + - name: Delete NAS Server + dellemc.powerstore.nasserver: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_id: "{{ nas_id }}" + state: "absent" + @@ -285,4 +320,5 @@ Authors ~~~~~~~ - Arindam Datta (@dattaarindam) +- Jennifer John (@johnj9) diff --git a/galaxy.yml b/galaxy.yml index 60ecf6f..e22756b 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -9,7 +9,7 @@ namespace: dellemc name: powerstore # The version of the collection. Must be compatible with semantic versioning -version: 2.1.0 +version: 2.2.0 # The path to the Markdown (.md) readme file. This path is relative to the root of the collection readme: README.md @@ -28,6 +28,7 @@ authors: - Trisha Datta - Ananthu S Kuttattu - Pavan Mudunuri + - Jennifer John ### OPTIONAL but strongly recommended # A short summary description of the collection @@ -50,13 +51,13 @@ tags: [storage] dependencies: {} # The URL of the originating SCM repository -repository: https://github.com/dell/ansible-powerstore/tree/2.1.0 +repository: https://github.com/dell/ansible-powerstore/tree/2.2.0 # The URL to any online docs -documentation: https://github.com/dell/ansible-powerstore/tree/2.1.0/docs +documentation: https://github.com/dell/ansible-powerstore/tree/2.2.0/docs # The URL to the homepage of the collection/project -homepage: https://github.com/dell/ansible-powerstore/tree/2.1.0 +homepage: https://github.com/dell/ansible-powerstore/tree/2.2.0 # The URL to the collection issue tracker issues: https://www.dell.com/community/Automation/bd-p/Automation diff --git a/playbooks/modules/cluster.yml b/playbooks/modules/cluster.yml index 65cb968..50cbaa8 100644 --- a/playbooks/modules/cluster.yml +++ b/playbooks/modules/cluster.yml @@ -105,7 +105,7 @@ appliances: - link_local_address: "1.2.x.x" name: "Ansible-cluster" - derive_failure_tolerance_level: "Double" + drive_failure_tolerance_level: "Double" dns_servers: - "1.1.x.x" ntp_servers: @@ -144,7 +144,7 @@ appliances: - link_local_address: "1.2.x.x" name: "Ansible-cluster" - derive_failure_tolerance_level: "Double" + drive_failure_tolerance_level: "Double" dns_servers: - "1.1.x.x" ntp_servers: diff --git a/playbooks/modules/filesystem.yml b/playbooks/modules/filesystem.yml index 453c965..285d7b3 100644 --- a/playbooks/modules/filesystem.yml +++ b/playbooks/modules/filesystem.yml @@ -229,3 +229,51 @@ filesystem_name: "{{ filesystem_name_prime }}" nas_server: "{{ nas_server_id }}" state: "absent" + + - name: Clone File System + dellemc.powerstore.filesystem: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + filesystem_name: "{{ filesystem_name }}" + nas_server: "{{ nas_server_id }}" + clone_filesystem: + name: "Test_Clone" + description: "{{ description }}" + access_policy: "UNIX" + locking_policy: "Advisory" + folder_rename_policy: "All_Allowed" + is_smb_sync_writes_enabled: true + is_smb_no_notify_enabled: true + is_smb_op_locks_enabled: true + is_smb_notify_on_access_enabled: true + is_smb_notify_on_write_enabled: true + smb_notify_on_change_dir_depth: 32 + is_async_MTime_enabled: false + file_events_publishing_mode: "All" + flr_attributes: + force_clone: false + state: "present" + + - name: Refresh File System + dellemc.powerstore.filesystem: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + snapshot_name: "Refresh_test" + nas_server: "{{ nas_server_id }}" + refresh_filesystem: true + state: "present" + + - name: Restore File System + dellemc.powerstore.filesystem: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + snapshot_id: "xxx-xxx-xxx" + restore_filesystem: true + backup_snap_name: "Restore_test" + state: "present" diff --git a/playbooks/modules/info.yml b/playbooks/modules/info.yml index 283d3af..0896299 100644 --- a/playbooks/modules/info.yml +++ b/playbooks/modules/info.yml @@ -476,3 +476,12 @@ - filter_key: storage_protocol filter_operator: equal filter_value: SCSI + + - name: Get list of discovered appliance + dellemc.powerstore.info: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + gather_subset: + - discovered_appliance diff --git a/playbooks/modules/nasserver.yml b/playbooks/modules/nasserver.yml index 4b725ae..c932230 100644 --- a/playbooks/modules/nasserver.yml +++ b/playbooks/modules/nasserver.yml @@ -14,6 +14,22 @@ prefered_node: "N2" tasks: + - name: Create NAS Server + dellemc.powerstore.nasserver: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_name: "{{ nas_server_name }}" + description: "{{ description }}" + current_unix_directory_service: "LDAP" + default_unix_user: "user1" + default_windows_user: "user2" + is_username_translation_enabled: true + is_auto_user_mapping_enabled: true + protection_policy: "ansible_policy" + state: "present" + - name: Get details of NAS Server by name register: result_nas dellemc.powerstore.nasserver: @@ -122,12 +138,11 @@ protection_policy: "" state: "present" - - name: Disassociate protection policy from a NAS Server - Idempotency + - name: Delete NAS Server dellemc.powerstore.nasserver: array_ip: "{{ array_ip }}" validate_certs: "{{ validate_certs }}" user: "{{ user }}" password: "{{ password }}" nas_server_name: "{{ nas_server_name }}" - protection_policy: "" - state: "present" + state: "absent" diff --git a/plugins/modules/certificate.py b/plugins/modules/certificate.py index 389b0c2..d231010 100644 --- a/plugins/modules/certificate.py +++ b/plugins/modules/certificate.py @@ -262,7 +262,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreCertificate(object): diff --git a/plugins/modules/cluster.py b/plugins/modules/cluster.py index a9f281c..bd775f3 100644 --- a/plugins/modules/cluster.py +++ b/plugins/modules/cluster.py @@ -357,7 +357,7 @@ appliances: - link_local_address: "1.2.x.x" name: "Ansible_cluster" - derive_failure_tolerance_level: "Double" + drive_failure_tolerance_level: "Double" dns_servers: - "1.1.x.x" ntp_servers: @@ -396,7 +396,7 @@ appliances: - link_local_address: "1.2.x.x" name: "Ansible_cluster" - derive_failure_tolerance_level: "Double" + drive_failure_tolerance_level: "Double" dns_servers: - "1.1.x.x" ntp_servers: @@ -627,7 +627,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreCluster(object): diff --git a/plugins/modules/dns.py b/plugins/modules/dns.py index b98aa0c..910e290 100644 --- a/plugins/modules/dns.py +++ b/plugins/modules/dns.py @@ -127,7 +127,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreDns(object): diff --git a/plugins/modules/email.py b/plugins/modules/email.py index 787a48c..15c3970 100644 --- a/plugins/modules/email.py +++ b/plugins/modules/email.py @@ -205,7 +205,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreEmail(object): diff --git a/plugins/modules/filesystem.py b/plugins/modules/filesystem.py index b5f4bf9..4840d05 100644 --- a/plugins/modules/filesystem.py +++ b/plugins/modules/filesystem.py @@ -15,11 +15,13 @@ description: - Supports the provisioning operations on a filesystem such as create, modify, delete and get the details of a filesystem. +- Supports clone, refresh and restore operations on a filesystem. extends_documentation_fragment: - dellemc.powerstore.powerstore author: - Arindam Datta (@dattaarindam) - Trisha Datta (@trisha-dell) +- Pavan Mudunuri(@Pavan-Mudunuri) options: filesystem_name: description: @@ -225,6 +227,128 @@ - Cannot be modified. choices: ['VMWARE_8K', 'VMWARE_16K', 'VMWARE_32K', 'VMWARE_64K'] type: str + clone_filesystem: + description: + - The attributes for filesystem clone. + type: dict + suboptions: + name: + description: + - Name of the clone. + - It can only be provided during creation of a filesystem clone. + type: str + description: + description: + - Description of the clone. + type: str + access_policy: + description: + - File system security access policies. + - C(Native) - Native Security. + - C(UNIX) - UNIX Security. + - C(Windows) - Windows Security. + choices: ['Native', 'UNIX', 'Windows'] + type: str + locking_policy: + description: + - File system locking policies. + - C(Advisory)- No lock checking for NFS and honor SMB lock range only for SMB. + - C(Mandatory)- Honor SMB and NFS lock range. + choices: ['Advisory', 'Mandatory'] + type: str + folder_rename_policy: + description: + - File system folder rename policies for the file system with + multi-protocol access enabled. + - C(All_Allowed) - All protocols are allowed to rename directories without + any restrictions. + - C(SMB_Forbidden) - A directory rename from the SMB protocol will be + denied if at least one file is opened in the directory or in one of its + child directories. + - C(All_Forbidden) - Any directory rename request will be denied regardless + of the protocol used, if at least one file is opened in the directory + or in one of its child directories. + choices: ['All_Allowed', 'SMB_Forbidden', 'All_Forbidden'] + type: str + is_smb_sync_writes_enabled: + description: + - Indicates whether the synchronous writes option is enabled on the + file system. + type: bool + is_smb_no_notify_enabled: + description: + - Indicates whether notifications of changes to directory file + structure are enabled. + type: bool + is_smb_op_locks_enabled: + description: + - Indicates whether opportunistic file locking is enabled on the file + system. + type: bool + is_smb_notify_on_access_enabled: + description: + - Indicates whether file access notifications are enabled on the file + system. + type: bool + is_smb_notify_on_write_enabled: + description: + - Indicates whether file write notifications are enabled on the file + system. + type: bool + smb_notify_on_change_dir_depth: + description: + - Determines the lowest directory level to which the + enabled notifications apply. minimum value is C(1). + type: int + is_async_MTime_enabled: + description: + - Indicates whether asynchronous MTIME is enabled on the file system. + type: bool + file_events_publishing_mode: + description: + - State of the event notification services for all file systems of the NAS server. + - C(None) - File event notifications are disabled for this file system. + - C(SMB_Only) - SMB notifications are enabled for this file system. + - C(NFS_Only) - NFS notifications are enabled for this file system. + - C(All) - SMB and NFS notifications are enabled for this file system. + choices: ['None', 'SMB_Only', 'NFS_Only', 'All'] + type: str + flr_attributes: + description: + - The attributes for file retention. + type: dict + suboptions: + force_clone: + description: + - Specifies whether an FLR-C file system should be cloned. + - C(true) - means cloning an FLR-C file system is allowed. + - C(false) - means cloning an FLR-C file system is not allowed. + and any attempt to do so will return an error. + type: bool + snapshot_name: + description: + - The name of the filesystem snapshot. + - Specify either snapshot name or ID (but not both) for restore and refresh operations. + type: str + snapshot_id: + description: + - The ID of the Snapshot. + - Specify either snapshot name or ID (but not both) for restore and refresh operations. + type: str + refresh_filesystem: + description: + - Specifies to refresh filesystem. + - Mandatory only for refresh filesystem. + type: bool + restore_filesystem: + description: + - Specifies to restore filesystem. + - Mandatory only for restore filesystem. + type: bool + backup_snap_name: + description: + - Name of the backup snap to be created before the restore operation occurs. + type: str state: description: - Define whether the filesystem should exist or not. @@ -237,6 +361,7 @@ - The I(check_mode) is not supported. - The pattern for I(minimum_retention), I(default_retention) and I(maximum_retention) is (^\d+[DMY])|(^infinite$). +- Filesystem snapshot can be created using filesystem_snapshot module. ''' EXAMPLES = r''' @@ -312,6 +437,54 @@ password: "{{password}}" filesystem_id: "{{result_fs.filesystem_details.id}}" state: "absent" + + - name: Clone File System + dellemc.powerstore.filesystem: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + filesystem_name: 'Atest' + nas_server: 'Test_Nas' + clone_filesystem: + name: "Test_ansible" + description: "Test" + access_policy: "UNIX" + locking_policy: "Advisory" + folder_rename_policy: "All_Allowed" + is_smb_sync_writes_enabled: true + is_smb_no_notify_enabled: true + is_smb_op_locks_enabled: true + is_smb_notify_on_access_enabled: true + is_smb_notify_on_write_enabled: true + smb_notify_on_change_dir_depth: 32 + is_async_MTime_enabled: false + file_events_publishing_mode: "All" + flr_attributes: + force_clone: false + state: "present" + + - name: Refresh File System + dellemc.powerstore.filesystem: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + snapshot_name: "Refresh_test" + nas_server: 'Sample_NAS' + refresh_filesystem: true + state: "present" + + - name: Restore File System + dellemc.powerstore.filesystem: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + snapshot_id: "xxx-xxx-xxx" + restore_filesystem: true + backup_snap_name: "Restore_test" + state: "present" ''' RETURN = r''' @@ -320,6 +493,21 @@ returned: always type: bool sample: "false" +is_filesystem_cloned: + description: Whether or not the clone of filesystem is created. + returned: always + type: bool + sample: "false" +is_filesystem_refreshed: + description: Whether or not the filesystem is refreshed. + returned: always + type: bool + sample: "false" +is_filesystem_restored: + description: Whether or not the filesystem is restored. + returned: always + type: bool + sample: "false" filesystem_details: description: Details of the filesystem. returned: When filesystem exists @@ -552,7 +740,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreFileSystem(object): @@ -568,17 +756,15 @@ def __init__(self): self.module_params = utils.get_powerstore_management_host_parameters() self.module_params.update(get_powerstore_filesystem_parameters()) - mutually_exclusive = [['filesystem_name', 'filesystem_id']] - required_one_of = [['filesystem_name', 'filesystem_id']] - required_together = [['filesystem_name', 'nas_server']] + mutually_exclusive = [['filesystem_name', 'filesystem_id'], ['snapshot_name', 'snapshot_id']] + required_one_of = [['filesystem_name', 'filesystem_id', 'snapshot_name', 'snapshot_id']] # initialize the Ansible module self.module = AnsibleModule( argument_spec=self.module_params, supports_check_mode=False, mutually_exclusive=mutually_exclusive, - required_one_of=required_one_of, - required_together=required_together + required_one_of=required_one_of ) msg = 'HAS_PY4PS = {0} , IMPORT_ERROR = ' \ '{1}'.format(HAS_PY4PS, IMPORT_ERROR) @@ -1093,6 +1279,115 @@ def validate_modify(self, fs_details): LOG.error(msg) self.module.fail_json(msg=msg) + def clone_filesystem_dict_params(self, clone_filesystem): + adv_parameters = {} + adv_param_list_enum = [ + 'name', 'description', 'access_policy', 'locking_policy', + 'folder_rename_policy', 'is_smb_sync_writes_enabled', + 'is_smb_no_notify_enabled', 'is_smb_op_locks_enabled', + 'is_smb_notify_on_access_enabled', 'is_smb_notify_on_write_enabled', + 'smb_notify_on_change_dir_depth', 'is_async_MTime_enabled', + 'file_events_publishing_mode', 'flr_attributes' + ] + + for param in adv_param_list_enum: + if clone_filesystem[param] is not None: + adv_parameters[param] = clone_filesystem[param] + return adv_parameters + + def clone_filesystem(self, filesystem_id, clone_filesystem): + """Clone filesystem""" + try: + LOG.info("Cloning filesystem") + adv_parameters = self.clone_filesystem_dict_params(clone_filesystem) + resp = self.provisioning.clone_filesystem(filesystem_id, + advance_parameters=adv_parameters) + LOG.debug(resp) + return resp["id"] + except Exception as e: + errormsg = f"Cloning filesystem failed with error {str(e)}" + LOG.error(errormsg) + self.module.fail_json(msg=errormsg, **utils.failure_codes(e)) + + def verify_required_together_params(self, filesystem_name=None, + snapshot_name=None, + nas_server=None): + if (filesystem_name or snapshot_name) and not nas_server: + errormsg = "nas_server is required along with, filesystem_name or snapshot_name" + LOG.error(errormsg) + self.module.fail_json(msg=errormsg) + elif nas_server and not (filesystem_name or snapshot_name): + errormsg = "filesystem_name or snapshot_name is required along with, nas_server" + LOG.error(errormsg) + self.module.fail_json(msg=errormsg) + + def get_snapshot_details_by_name(self, name, nas_server): + try: + snap_details = self.protection.get_filesystem_snapshot_details_by_name(snapshot_name=name, + nas_server_id=nas_server) + return snap_details[0] if snap_details else None + except Exception as e: + LOG.error("Error getting snapshot details by name: %s", str(e)) + raise + + def get_snap_details(self, snapshot_id=None, + snapshot_name=None, + nas_server=None, + backup_snap_name=None): + try: + snap_details = None + if snapshot_id: + snap_details = self.protection.get_filesystem_snapshot_details(snapshot_id=snapshot_id) + elif snapshot_name and nas_server: + snap_details = self.get_snapshot_details_by_name(snapshot_name, nas_server) + if not snap_details: + errormsg = f"Instance with name {str(snapshot_name)} was not found." + LOG.error(errormsg) + self.module.fail_json(msg=errormsg) + elif backup_snap_name and nas_server: + snap_details = self.get_snapshot_details_by_name(backup_snap_name, nas_server) + if not snap_details: + return None + return snap_details + except Exception as e: + errormsg = f"Failed to get filesystem snapshot {str(e)}" + LOG.error(errormsg) + self.module.fail_json(msg=errormsg, **utils.failure_codes(e)) + + def refresh_filesystem(self, snapshot_id=None): + """Refresh filesystem""" + try: + LOG.info("Refreshing filesystem") + self.provisioning.refresh_filesystem(snapshot_id) + return True + except Exception as e: + errormsg = f"Refreshing filesystem failed with error {str(e)}" + LOG.error(errormsg) + self.module.fail_json(msg=errormsg, **utils.failure_codes(e)) + + def restore_filesystem(self, snapshot_id=None, + backup_snap_name=None): + """Restore filesystem""" + try: + LOG.info("Restoring filesystem") + self.provisioning.restore_filesystem(snapshot_id, backup_snap_name) + return True + except Exception as e: + errormsg = f"Restoring filesystem failed with error {str(e)}" + LOG.error(errormsg) + self.module.fail_json(msg=errormsg, **utils.failure_codes(e)) + + def get_clone(self, clone_name, nas_server_id): + """Get Clone filesystem""" + if clone_name: + clone = self.get_filesystem_details(filesystem_name=clone_name, + nas_server_id=nas_server_id) + return clone + else: + errormsg = "'name' parameter is required in clone_filesystem" + LOG.error(errormsg) + self.module.fail_json(msg=errormsg) + def perform_module_operation(self): clusters = self.get_clusters() if len(clusters) > 0: @@ -1108,15 +1403,24 @@ def perform_module_operation(self): size = self.module.params['size'] cap_unit = self.module.params['cap_unit'] protection_policy = self.module.params['protection_policy'] + clone_filesystem = self.module.params['clone_filesystem'] + refresh_filesystem = self.module.params['refresh_filesystem'] + restore_filesystem = self.module.params['restore_filesystem'] + snapshot_name = self.module.params['snapshot_name'] + snapshot_id = self.module.params['snapshot_id'] + backup_snap_name = self.module.params['backup_snap_name'] state = self.module.params['state'] # result is a dictionary to contain end state and filesystem details changed = False + is_filesystem_restored = False + is_filesystem_refreshed = False + is_filesystem_cloned = False result = dict( changed=False, filesystem_details=None ) - + self.verify_required_together_params(filesystem_name, snapshot_name, nas_server) fs_id = None to_modify = False to_modify_dict = None @@ -1128,7 +1432,7 @@ def perform_module_operation(self): self.validate_modify(fs_details) - if not fs_details and state == 'present': + if not fs_details and state == 'present' and not (snapshot_id or snapshot_name or clone_filesystem): fs_id = self.create_filesystem( name=filesystem_name, nas_server_id=nas_server, @@ -1150,6 +1454,54 @@ def perform_module_operation(self): modify_parameters=to_modify_dict) changed = True + if state == 'present' and clone_filesystem: + if filesystem_id: + nas_server = fs_details['nas_server']['id'] + clone = self.get_clone(clone_name=clone_filesystem['name'], + nas_server_id=nas_server) + if not clone: + if filesystem_name and nas_server: + fs_details = self.get_filesystem_details(filesystem_name=filesystem_name, + nas_server_id=nas_server) + filesystem_id = fs_details['id'] + self.clone_filesystem(filesystem_id, clone_filesystem) + changed = True + is_filesystem_cloned = True + + if (snapshot_id or snapshot_name) and \ + not (refresh_filesystem or restore_filesystem): + errormsg = "Either refresh_filesystem or restore_filesystem is required" + LOG.error(errormsg) + self.module.fail_json(msg=errormsg) + elif (snapshot_id or snapshot_name) and \ + (refresh_filesystem or restore_filesystem): + snap = self.get_snap_details(snapshot_id=snapshot_id, + snapshot_name=snapshot_name, + nas_server=nas_server) + fs_id = snap['parent_id'] + snapshot_id = snap['id'] + nas_server = snap['nas_server']['id'] + + if state == 'present' and refresh_filesystem and \ + (snapshot_id or snapshot_name): + self.refresh_filesystem(snapshot_id=snapshot_id) + fs_details = self.get_filesystem_details(filesystem_id=fs_id) + changed = True + is_filesystem_refreshed = True + + if state == 'present' and restore_filesystem and \ + (snapshot_id or snapshot_name): + backup_snap = None + if backup_snap_name: + backup_snap = self.get_snap_details(nas_server=nas_server, + backup_snap_name=backup_snap_name) + if not backup_snap: + self.restore_filesystem(snapshot_id=snapshot_id, + backup_snap_name=backup_snap_name) + changed = True + is_filesystem_restored = True + fs_details = self.get_filesystem_details(filesystem_id=fs_id) + if state == 'absent' and fs_details: self.delete_filesystem(filesystem_id=fs_id) fs_details = None @@ -1160,6 +1512,9 @@ def perform_module_operation(self): filesystem_id=fs_id) result['changed'] = changed + result['is_filesystem_restored'] = is_filesystem_restored + result['is_filesystem_refreshed'] = is_filesystem_refreshed + result['is_filesystem_cloned'] = is_filesystem_cloned result['filesystem_details'] = fs_details self.module.exit_json(**result) @@ -1213,6 +1568,30 @@ def get_powerstore_filesystem_parameters(): policy_interval=dict(type='int') ) ), + clone_filesystem=dict( + type='dict', options=dict( + name=dict(type='str'), + description=dict(type='str'), + access_policy=dict(choices=['Native', 'UNIX', 'Windows'], type='str'), + locking_policy=dict(choices=['Advisory', 'Mandatory'], type='str'), + folder_rename_policy=dict(choices=['All_Allowed', 'SMB_Forbidden', 'All_Forbidden'], type='str'), + is_smb_sync_writes_enabled=dict(type='bool'), + is_smb_no_notify_enabled=dict(type='bool'), + is_smb_op_locks_enabled=dict(type='bool'), + is_smb_notify_on_access_enabled=dict(type='bool'), + is_smb_notify_on_write_enabled=dict(type='bool'), + smb_notify_on_change_dir_depth=dict(type='int'), + is_async_MTime_enabled=dict(type='bool'), + file_events_publishing_mode=dict(choices=['All', 'None', 'SMB_Only', 'NFS_Only'], type='str'), + flr_attributes=dict(type='dict', + options=dict(force_clone=dict(type='bool'))) + ) + ), + snapshot_name=dict(type='str'), + snapshot_id=dict(type='str'), + refresh_filesystem=dict(type='bool'), + restore_filesystem=dict(type='bool'), + backup_snap_name=dict(type='str'), smb_properties=dict( type='dict', options=dict( is_smb_sync_writes_enabled=dict(type='bool'), diff --git a/plugins/modules/filesystem_snapshot.py b/plugins/modules/filesystem_snapshot.py index 27bcb73..a884eaf 100644 --- a/plugins/modules/filesystem_snapshot.py +++ b/plugins/modules/filesystem_snapshot.py @@ -253,7 +253,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreFilesystemSnapshot(object): diff --git a/plugins/modules/host.py b/plugins/modules/host.py index 3f76d96..e6e9206 100644 --- a/plugins/modules/host.py +++ b/plugins/modules/host.py @@ -373,7 +373,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' # DO NOT CHANGE BELOW PORT_TYPES SEQUENCE AS ITS USED IN SCRIPT USING INDEX PORT_TYPES = ["iSCSI", "FC", "NVMe"] diff --git a/plugins/modules/hostgroup.py b/plugins/modules/hostgroup.py index 01ad3e7..6a52643 100644 --- a/plugins/modules/hostgroup.py +++ b/plugins/modules/hostgroup.py @@ -224,7 +224,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreHostgroup(object): diff --git a/plugins/modules/info.py b/plugins/modules/info.py index 45647ca..5a695b8 100644 --- a/plugins/modules/info.py +++ b/plugins/modules/info.py @@ -23,8 +23,8 @@ replication groups, and remote system. - Virtualization module includes vCenters and virtual volumes. - Configuration module includes cluster nodes, networks, roles, local users, - appliances, security configs, certificates, AD/LDAP servers, LDAP accounts, - and LDAP domain. + appliances, discovered appliances, security configs, certificates, + AD/LDAP servers, LDAP accounts, and LDAP domain. - It also includes DNS/NTP servers, smtp configs, email destinations, remote support, and remote support contacts. author: @@ -76,6 +76,7 @@ - Virtual volumes - C(virtual_volume). - Storage containers - C(storage_container). - Replication groups - C(replication_group). + - Discovered appliances - C(discovered_appliance). required: true elements: str choices: [vol, vg, host, hg, node, protection_policy, snapshot_rule, @@ -85,7 +86,7 @@ ldap, security_config, certificate, dns, ntp, smtp_config, email_notification, remote_support, remote_support_contact, ldap_domain, vcenter, virtual_volume, storage_container, - replication_group] + replication_group, discovered_appliance] type: list filters: description: @@ -122,7 +123,8 @@ default: false notes: - Pagination is not supported for role, local user, security configs, LDAP - accounts and LDAP domain. If I(all_pages) is passed, it will be ignored. + accounts, discovered appliances and LDAP domain. If I(all_pages) is passed, + it will be ignored. - The I(check_mode) is supported. ''' @@ -366,7 +368,7 @@ - virtual_volume - replication_group -- name: Get list of storage containers +- name: Get list of storage containers and discovered appliances dellemc.powerstore.info: array_ip: "{{array_ip}}" validate_certs: "{{validate_certs}}" @@ -374,7 +376,7 @@ password: "{{password}}" gather_subset: - storage_container - + - discovered_appliance ''' RETURN = r''' @@ -388,7 +390,7 @@ description: API version of PowerStore array. returned: always type: str - sample: "2.1.0.0" + sample: "2.2.0.0" ActiveDirectory: description: Provides details of all active directories. type: list @@ -413,15 +415,86 @@ name: description: Name of the appliance. type: str + service_tag: + description: Dell service tag of the appliance. + type: str + express_service_code: + description: Express service code. + type: str model: description: Model type of the PowerStore. type: str + node_count: + description: Number of nodes deployed on an appliance. It was added + in version 3.0.0.0. + type: int + drive_failure_tolerance_level: + description: Drive failure tolerance level. + type: str + is_hyper_converged: + description: Whether the appliance is a hyper-converged appliance. + It was added in version 3.2.0.0. + type: bool + nodes: + description: Provides details of all nodes. + type: list + ip_pool_addresses: + description: Provides details of all IP pool addresses. + type: list + veth_ports: + description: Provides details of all veth ports. + type: list + virtual_volumes: + description: Provides details of all virtual volumes. + type: list + maintenance_windows: + description: Provides details of all maintenance windows. + type: list + fc_ports: + description: Provides details of all FC ports. + type: list + sas_ports: + description: Provides details of all SAS ports. + type: list + eth_ports: + description: Provides details of all Ethernet ports. + type: list + eth_be_ports: + description: Provides details of all eth_be_ports. It was added in + version 3.0.0.0. + type: list + software_installed: + description: Provides details of all software installed. + type: list + hardware: + description: Provides details of all hardware. + type: list + volumes: + description: Provides details of all volumes. + type: list sample: [ - { + { "id": "A1", + "name": "Appliance-WND8977", + "service_tag": "A1", + "express_service_code": "A1", "model": "PowerStore 1000T", - "name": "Appliance-WND8977" - } + "node_count": 1, + "drive_failure_tolerance_level": "None", + "is_hyper_converged": false, + "nodes": [], + "ip_pool_addresses": [], + "veth_ports": [], + "virtual_volumes": [], + "maintenance_windows": [], + "fc_ports": [], + "sas_ports": [], + "eth_ports": [], + "eth_be_ports": [], + "software_installed": [], + "hardware": [], + "volumes": [] + } ] Certificate: description: Provides details of all certificates. @@ -455,6 +528,92 @@ "name": "RT-D1006" } ] +DiscoveredAppliances: + description: Provides details of all discovered appliances. + type: list + returned: When C(discovered_appliance) is in a given I(gather_subset) + contains: + id: + description: ID of a discovered appliance. The local discovered + appliance has the id "0". + type: str + link_local_address: + description: Link local IPv4 address of the discovered appliance. + type: str + service_name: + description: Service name of the discovered appliance. + type: str + service_tag: + description: The Dell service tag. + type: str + state: + description: Possible unmanaged appliance states. + type: str + mode: + description: Storage access mode supported by the appliance. + type: str + model: + description: The model of the appliance. + type: str + express_service_code: + description: Express service code for the appliance. + type: str + is_local: + description: Indicates whether appliance is local or not. + type: bool + management_service_ready: + description: Indicates whether the management services are ready. + type: bool + software_version_compatibility: + description: Compatibility of the software version on an appliance + compared to the software version on the appliance + running the request. + type: str + build_version: + description: Build version of the installed software package + release. + type: str + build_id: + description: Build ID. + type: str + power_score: + description: Power rating of the appliance. + type: int + node_count: + description: Number of nodes deployed on an appliance. + type: int + is_unified_capable: + description: Indicates whether the appliance is capable of unified + configuration. + type: bool + drive_failure_tolerance_level_and_availability: + description: Drive failure tolerance level and availability. + type: list + is_hyper_converged: + description: Indicates whether the appliance is a hyper converged + or not. It was added in version 3.2.0.0. + type: bool + sample: [ + { + "id": "A1", + "link_local_address": "1.0.2.x", + "service_name": "Appliance-WND8977", + "service_tag": "A8977", + "state": "Unconfigured", + "mode": "Unified", + "model": "PowerStore 1000T", + "express_service_code": "A8977", + "is_local": true, + "management_service_ready": true, + "software_version_compatibility": "3.0.0.0", + "build_version": "3.0.0.0", + "build_id": "3202", + "power_score": 0, + "node_count": 2, + "is_unified_capable": true, + "is_hyper_converged": false + } + ] DNS: description: Provides details of all DNS servers. type: list @@ -1388,7 +1547,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreInfo(object): @@ -1574,6 +1733,10 @@ def __init__(self): 'storage_container': { 'func': self.configuration.get_storage_container_list, 'display_as': 'StorageContainers' + }, + 'discovered_appliance': { + 'func': self.configuration.get_discovered_appliances, + 'display_as': 'DiscoveredAppliances' } } LOG.info('Got Py4ps connection object %s', self.conn) @@ -1681,17 +1844,22 @@ def get_array_software_version(self): def perform_module_operation(self): clusters = self.get_clusters() + cluster_state = '' if len(clusters) > 0: self.cluster_name = clusters[0]['name'] self.cluster_global_id = clusters[0]['id'] + cluster_state = clusters[0]['state'] else: self.module.fail_json(msg="Unable to find any active cluster on" " this array ") - array_soft_ver = self.get_array_software_version() - self.result.update(Cluster=clusters, - Array_Software_Version=array_soft_ver) + Array_Software_Version=None) + if cluster_state == 'Configured': + array_soft_ver = self.get_array_software_version() + self.result.update(Cluster=clusters, + Array_Software_Version=array_soft_ver) + subset = self.module.params['gather_subset'] filters = self.module.params['filters'] all_pages = self.module.params['all_pages'] @@ -1732,7 +1900,7 @@ def get_powerstore_info_parameters(): 'remote_support', 'remote_support_contact', 'ldap_account', 'ldap_domain', 'vcenter', 'virtual_volume', 'storage_container', - 'replication_group']), + 'replication_group', 'discovered_appliance']), filters=dict(type='list', required=False, elements='dict', options=dict(filter_key=dict(type='str', required=True, no_log=False), diff --git a/plugins/modules/job.py b/plugins/modules/job.py index 7554a24..8dbd831 100644 --- a/plugins/modules/job.py +++ b/plugins/modules/job.py @@ -174,7 +174,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreJob(object): diff --git a/plugins/modules/ldap_account.py b/plugins/modules/ldap_account.py index ab6c167..01c79f6 100644 --- a/plugins/modules/ldap_account.py +++ b/plugins/modules/ldap_account.py @@ -173,7 +173,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreLDAPAccount(object): diff --git a/plugins/modules/ldap_domain.py b/plugins/modules/ldap_domain.py index 2b13610..5664c86 100644 --- a/plugins/modules/ldap_domain.py +++ b/plugins/modules/ldap_domain.py @@ -354,7 +354,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreLDAPDomain(object): diff --git a/plugins/modules/local_user.py b/plugins/modules/local_user.py index 5bc2f4b..18f3d59 100644 --- a/plugins/modules/local_user.py +++ b/plugins/modules/local_user.py @@ -185,7 +185,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreLocalUser(object): diff --git a/plugins/modules/nasserver.py b/plugins/modules/nasserver.py index caa0085..df5e12d 100644 --- a/plugins/modules/nasserver.py +++ b/plugins/modules/nasserver.py @@ -13,11 +13,13 @@ version_added: '1.1.0' short_description: NAS Server operations for PowerStore Storage system description: -- Supports getting the details and modifying the attributes of a NAS server. +- Supports getting the details, creating, modifying the attributes of a NAS server + and deleting a NAS server. extends_documentation_fragment: - dellemc.powerstore.powerstore author: - Arindam Datta (@dattaarindam) +- Jennifer John (@johnj9) options: nas_server_name: description: @@ -67,6 +69,18 @@ - Name/ID of the protection policy applied to the nas server. - Policy can be removed by passing an empty string in the I(protection_policy) parameter. type: str + is_username_translation_enabled: + description: + - Enable the possibility to match a Windows account with an Unix account with different names. + type: bool + version_added: '2.2.0' + is_auto_user_mapping_enabled: + description: + - To automatically generate the unix user (uid), if the windows user does + not have any in the configured Unix Directory Service (UDS). + - In a pure SMB or non multi-protocol environment, this should be set to true. + type: bool + version_added: '2.2.0' state: description: - Define whether the nas server should exist or not. @@ -82,57 +96,82 @@ EXAMPLES = r''' + - name: Create a NAS Server + dellemc.powerstore.nasserver: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_name: "test-nas-server" + description: "NAS Server test" + current_unix_directory_service: "LDAP" + default_unix_user: "user1" + default_windows_user: "user2" + is_username_translation_enabled: true + is_auto_user_mapping_enabled: true + protection_policy: "ansible_policy" + state: "present" + - name: Get details of NAS Server by name dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_name: "{{nas_server_name}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_name: "{{ nas_server_name }}" state: "present" - name: Get Details of NAS Server by ID dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_id: "{{nas_id}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_id: "{{ nas_id }}" state: "present" - name: Rename NAS Server by Name dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_name: "{{nas_server_name}}" - nas_server_new_name : "{{nas_server_new_name}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_name: "{{ nas_server_name }}" + nas_server_new_name : "{{ nas_server_new_name }}" state: "present" - name: Modify NAS Server attributes by ID dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_id: "{{nas_id}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_id: "{{ nas_id }}" current_unix_directory_service: "LOCAL_FILES" - current_node: "{{cur_node_n1}}" - preferred_node: "{{prefered_node}}" + current_node: "{{ cur_node_n1 }}" + preferred_node: "{{ prefered_node }}" protection_policy: "protection_policy_1" state: "present" - name: Remove protection policy dellemc.powerstore.nasserver: - array_ip: "{{array_ip}}" - validate_certs: "{{validate_certs}}" - user: "{{user}}" - password: "{{password}}" - nas_server_id: "{{nas_id}}" + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_id: "{{ nas_id }}" protection_policy: "" state: "present" + - name: Delete NAS Server + dellemc.powerstore.nasserver: + array_ip: "{{ array_ip }}" + validate_certs: "{{ validate_certs }}" + user: "{{ user }}" + password: "{{ password }}" + nas_server_id: "{{ nas_id }}" + state: "absent" + ''' RETURN = r''' @@ -299,7 +338,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreNasServer(object): @@ -470,13 +509,30 @@ def get_clusters(self): LOG.error(msg) self.module.fail_json(msg=msg, **utils.failure_codes(e)) + def create_nas_server(self, payload): + """Create a NAS Server. + + :param payload: The payload to create the NAS Server + :type: dict + :return: NAS server ID on success else raise exception + :rtype: str + """ + try: + msg = f'Creating NAS server {payload.get("name")}' + LOG.info(msg) + return self.provisioning.create_nasserver(payload).get('id') + except Exception as e: + msg = f'Creating NAS server {payload.get("name")} failed with error {str(e)}' + LOG.error(msg) + self.module.fail_json(msg=msg, **utils.failure_codes(e)) + def to_modify_nasserver(self, nasserver_details): """Determines if any modification required on a specific nas server instance.""" try: LOG.info("Checking if Modify required for nas server ") - modify_parameters = dict() + modify_parameters = get_modify_dict(self.module.params, nasserver_details) description = self.module.params['description'] @@ -559,6 +615,23 @@ def modify_nasserver(self, nasserver_id, modify_parameters): LOG.error(msg) self.module.fail_json(msg=msg, **utils.failure_codes(e)) + def delete_nas_server(self, nas_server_id): + """Delete a NAS Server. + + :param nas_server_id: The ID of the NAS Server to delete + :type nas_server_id: str + :return: None on success else raise exception + :rtype: None + """ + try: + msg = f'Deleting nas server {nas_server_id}' + LOG.info(msg) + return self.provisioning.delete_nasserver(nas_server_id) + except Exception as e: + msg = f'Deleting NAS server {nas_server_id} failed with error {str(e)}' + LOG.error(msg) + self.module.fail_json(msg=msg, **utils.failure_codes(e)) + def get_enum_keys(self, user_input): """Get the ENUM Keys for user input string""" try: @@ -577,6 +650,20 @@ def get_enum_keys(self, user_input): LOG.error(msg) self.module.fail_json(msg=msg, **utils.failure_codes(e)) + def perform_module_exit(self, state, changed, result, nasserver_details, nas_id): + if changed: + nasserver_details = self.get_nas_server( + nas_server_id=nas_id) + if state == 'present': + nasserver_details['current_node'] = self.get_node_id( + nasserver_details.get('current_node_id')) + nasserver_details['preferred_node'] = self.get_node_id( + nasserver_details.get('preferred_node_id')) + + result['changed'] = changed + result['nasserver_details'] = nasserver_details + self.module.exit_json(**result) + def perform_module_operation(self): clusters = self.get_clusters() if len(clusters) > 0: @@ -635,11 +722,10 @@ def perform_module_operation(self): LOG.debug(log_msg) if not nasserver_details and state == 'present': - msg = "Creation of NAS Server is not currently supported " \ - "through Ansible Module " - - LOG.error(msg) - self.module.fail_json(msg=msg) + nas_id = self.create_nas_server( + payload=create_nas_server_payload(self.module.params, + self.protection_policy_id)) + changed = True if to_modify and state == 'present': self.modify_nasserver(nasserver_id=nas_id, @@ -647,22 +733,10 @@ def perform_module_operation(self): changed = True if state == 'absent' and nasserver_details: - msg = "Deletion of NAS Server is not currently supported " \ - "through Ansible Module" - LOG.error(msg) - self.module.fail_json(msg=msg) - - if state == 'present' and nasserver_details: - nasserver_details = self.get_nas_server( - nas_server_id=nas_id) - nasserver_details['current_node'] = self.get_node_id( - nasserver_details['current_node_id']) - nasserver_details['preferred_node'] = self.get_node_id( - nasserver_details['preferred_node_id']) + self.delete_nas_server(nas_server_id=nas_id) + changed = True - result['changed'] = changed - result['nasserver_details'] = nasserver_details - self.module.exit_json(**result) + self.perform_module_exit(state, changed, result, nasserver_details, nas_id) def get_powerstore_nasserver_parameters(): @@ -676,6 +750,8 @@ def get_powerstore_nasserver_parameters(): current_node=dict(required=False, type='str'), preferred_node=dict(required=False, type='str'), protection_policy=dict(required=False, type='str'), + is_username_translation_enabled=dict(required=False, type='bool'), + is_auto_user_mapping_enabled=dict(required=False, type='bool'), current_unix_directory_service=dict(required=False, type='str', choices=['NIS', 'LDAP', @@ -688,6 +764,38 @@ def get_powerstore_nasserver_parameters(): ) +def create_nas_server_payload(params, protection_policy_id): + """Create a payload for creating a NAS Server. + + :param params: The input params + :type params: dict + :param protection_policy_id: The ID of the protection policy for the NAS Server + :type protection_policy_id: str + :return: The payload for creating the NAS Server + :rtype: dict + """ + payload = { + "name": params.get('nas_server_name'), + "description": params.get('description'), + "current_unix_directory_service": params.get('current_unix_directory_service'), + "default_unix_user": params.get('default_unix_user'), + "default_windows_user": params.get('default_windows_user'), + "is_username_translation_enabled": params.get('is_username_translation_enabled'), + "is_auto_user_mapping_enabled": params.get('is_auto_user_mapping_enabled'), + "protection_policy_id": protection_policy_id + } + return payload + + +def get_modify_dict(params, nasserver_details): + modify_dict = dict() + keys = ['is_username_translation_enabled', 'is_auto_user_mapping_enabled'] + for key in keys: + if params.get(key) is not None and nasserver_details.get(key) != params.get(key): + modify_dict[key] = params.get(key) + return modify_dict + + def main(): """ Create PowerStore NAS Server object and perform action on it based on user input from playbook """ diff --git a/plugins/modules/network.py b/plugins/modules/network.py index 57db7d0..1f13d7f 100644 --- a/plugins/modules/network.py +++ b/plugins/modules/network.py @@ -498,7 +498,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreNetwork(object): diff --git a/plugins/modules/nfs.py b/plugins/modules/nfs.py index 414f3b8..9c5ab56 100644 --- a/plugins/modules/nfs.py +++ b/plugins/modules/nfs.py @@ -380,7 +380,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreNfsExport(object): diff --git a/plugins/modules/ntp.py b/plugins/modules/ntp.py index 7d14276..c0a092f 100644 --- a/plugins/modules/ntp.py +++ b/plugins/modules/ntp.py @@ -128,7 +128,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreNtp(object): diff --git a/plugins/modules/protectionpolicy.py b/plugins/modules/protectionpolicy.py index 0b2f548..6b97f82 100644 --- a/plugins/modules/protectionpolicy.py +++ b/plugins/modules/protectionpolicy.py @@ -241,7 +241,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreProtectionpolicy(object): diff --git a/plugins/modules/quota.py b/plugins/modules/quota.py index fbb3d68..7d8e804 100644 --- a/plugins/modules/quota.py +++ b/plugins/modules/quota.py @@ -364,7 +364,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreQuota(object): diff --git a/plugins/modules/remote_support.py b/plugins/modules/remote_support.py index 429d1c9..28f63f3 100644 --- a/plugins/modules/remote_support.py +++ b/plugins/modules/remote_support.py @@ -357,7 +357,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreRemoteSupport(object): diff --git a/plugins/modules/remote_support_contact.py b/plugins/modules/remote_support_contact.py index 95fff07..2e3610f 100644 --- a/plugins/modules/remote_support_contact.py +++ b/plugins/modules/remote_support_contact.py @@ -137,7 +137,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreRemoteSupportContact(object): diff --git a/plugins/modules/remotesystem.py b/plugins/modules/remotesystem.py index 89704c8..83fc1f1 100644 --- a/plugins/modules/remotesystem.py +++ b/plugins/modules/remotesystem.py @@ -308,7 +308,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreRemoteSystem(object): diff --git a/plugins/modules/replicationrule.py b/plugins/modules/replicationrule.py index 59b1bac..4eff362 100644 --- a/plugins/modules/replicationrule.py +++ b/plugins/modules/replicationrule.py @@ -197,7 +197,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreReplicationRule(object): diff --git a/plugins/modules/replicationsession.py b/plugins/modules/replicationsession.py index 8415849..30e4387 100644 --- a/plugins/modules/replicationsession.py +++ b/plugins/modules/replicationsession.py @@ -230,7 +230,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' """ =============================================================================== Idempotency table for the replication session ansible module on the basis of diff --git a/plugins/modules/role.py b/plugins/modules/role.py index dd78a31..3cee637 100644 --- a/plugins/modules/role.py +++ b/plugins/modules/role.py @@ -113,7 +113,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreRole(object): diff --git a/plugins/modules/security_config.py b/plugins/modules/security_config.py index 9a4c478..2b7a5db 100644 --- a/plugins/modules/security_config.py +++ b/plugins/modules/security_config.py @@ -116,7 +116,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreSecurityConfig(object): diff --git a/plugins/modules/smbshare.py b/plugins/modules/smbshare.py index c0e1529..7cfd656 100644 --- a/plugins/modules/smbshare.py +++ b/plugins/modules/smbshare.py @@ -311,7 +311,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreSMBShare(object): diff --git a/plugins/modules/smtp_config.py b/plugins/modules/smtp_config.py index fb09c84..803682b 100644 --- a/plugins/modules/smtp_config.py +++ b/plugins/modules/smtp_config.py @@ -139,7 +139,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreSmtpConfig(object): diff --git a/plugins/modules/snapshot.py b/plugins/modules/snapshot.py index 77e6454..6051535 100644 --- a/plugins/modules/snapshot.py +++ b/plugins/modules/snapshot.py @@ -344,7 +344,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreSnapshot(object): diff --git a/plugins/modules/snapshotrule.py b/plugins/modules/snapshotrule.py index 4bf91bf..e9e7a74 100644 --- a/plugins/modules/snapshotrule.py +++ b/plugins/modules/snapshotrule.py @@ -254,7 +254,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreSnapshotrule(object): diff --git a/plugins/modules/storage_container.py b/plugins/modules/storage_container.py index 7f77987..173e91b 100644 --- a/plugins/modules/storage_container.py +++ b/plugins/modules/storage_container.py @@ -361,7 +361,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreStorageContainer(object): diff --git a/plugins/modules/vcenter.py b/plugins/modules/vcenter.py index 93de5a1..cbd66e3 100644 --- a/plugins/modules/vcenter.py +++ b/plugins/modules/vcenter.py @@ -215,7 +215,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerstoreVCenter(object): diff --git a/plugins/modules/volume.py b/plugins/modules/volume.py index c3660f8..b59dad2 100644 --- a/plugins/modules/volume.py +++ b/plugins/modules/volume.py @@ -631,7 +631,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreVolume(object): diff --git a/plugins/modules/volumegroup.py b/plugins/modules/volumegroup.py index 5de5a56..d10510c 100644 --- a/plugins/modules/volumegroup.py +++ b/plugins/modules/volumegroup.py @@ -398,7 +398,7 @@ VERSION_ERROR = py4ps_version['unsupported_version_message'] # Application type -APPLICATION_TYPE = 'Ansible/2.1.0' +APPLICATION_TYPE = 'Ansible/2.2.0' class PowerStoreVolumeGroup(object): diff --git a/tests/sanity/ignore-2.13.txt b/tests/sanity/ignore-2.13.txt index 192bfe9..a80053c 100644 --- a/tests/sanity/ignore-2.13.txt +++ b/tests/sanity/ignore-2.13.txt @@ -2,6 +2,14 @@ plugins/modules/vcenter.py compile-2.7 plugins/modules/vcenter.py compile-3.5 plugins/modules/vcenter.py import-2.7 plugins/modules/vcenter.py import-3.5 +plugins/modules/nasserver.py import-2.7 +plugins/modules/nasserver.py compile-2.7 +plugins/modules/nasserver.py import-3.5 +plugins/modules/nasserver.py compile-3.5 +plugins/modules/filesystem.py compile-2.7 +plugins/modules/filesystem.py compile-3.5 +plugins/modules/filesystem.py import-2.7 +plugins/modules/filesystem.py import-3.5 plugins/modules/volume.py compile-2.7 plugins/modules/volume.py compile-3.5 plugins/modules/volume.py import-2.7 diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index 192bfe9..a80053c 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -2,6 +2,14 @@ plugins/modules/vcenter.py compile-2.7 plugins/modules/vcenter.py compile-3.5 plugins/modules/vcenter.py import-2.7 plugins/modules/vcenter.py import-3.5 +plugins/modules/nasserver.py import-2.7 +plugins/modules/nasserver.py compile-2.7 +plugins/modules/nasserver.py import-3.5 +plugins/modules/nasserver.py compile-3.5 +plugins/modules/filesystem.py compile-2.7 +plugins/modules/filesystem.py compile-3.5 +plugins/modules/filesystem.py import-2.7 +plugins/modules/filesystem.py import-3.5 plugins/modules/volume.py compile-2.7 plugins/modules/volume.py compile-3.5 plugins/modules/volume.py import-2.7 diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt index 192bfe9..a80053c 100644 --- a/tests/sanity/ignore-2.15.txt +++ b/tests/sanity/ignore-2.15.txt @@ -2,6 +2,14 @@ plugins/modules/vcenter.py compile-2.7 plugins/modules/vcenter.py compile-3.5 plugins/modules/vcenter.py import-2.7 plugins/modules/vcenter.py import-3.5 +plugins/modules/nasserver.py import-2.7 +plugins/modules/nasserver.py compile-2.7 +plugins/modules/nasserver.py import-3.5 +plugins/modules/nasserver.py compile-3.5 +plugins/modules/filesystem.py compile-2.7 +plugins/modules/filesystem.py compile-3.5 +plugins/modules/filesystem.py import-2.7 +plugins/modules/filesystem.py import-3.5 plugins/modules/volume.py compile-2.7 plugins/modules/volume.py compile-3.5 plugins/modules/volume.py import-2.7 diff --git a/tests/unit/plugins/module_utils/mock_filesystem_api.py b/tests/unit/plugins/module_utils/mock_filesystem_api.py index 30c1b8b..2730bfa 100644 --- a/tests/unit/plugins/module_utils/mock_filesystem_api.py +++ b/tests/unit/plugins/module_utils/mock_filesystem_api.py @@ -10,7 +10,6 @@ class MockFilesystemApi: - MODULE_UTILS_PATH = 'ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell.utils' FILESYSTEM_COMMON_ARGS = { "array_ip": '**.***.**.***', @@ -31,7 +30,13 @@ class MockFilesystemApi: "is_async_mtime_enabled": None, "file_events_publishing_mode": None, "flr_attributes": None, - "host_io_size": None + "host_io_size": None, + "clone_filesystem": None, + "snapshot_name": None, + "snapshot_id": None, + "refresh_filesystem": None, + "restore_filesystem": None, + "backup_snap_name": None } FS_NAME = "sample_filesystem" @@ -40,6 +45,7 @@ class MockFilesystemApi: NAS_ID = "6026056b-5405-0e36-7697-c285b9fa42b7" DESCRIPTION1 = "FS Testing" FILESYSTEM_TYPE = "Primary File system" + SNAP_ID = "6026056b-5405-0e36-7697-c4523fa42b7" FS_DETAILS_1 = [{ "access_policy": "UNIX", @@ -107,6 +113,51 @@ class MockFilesystemApi: "used_size_with_unit": "1.51 GB" }] + FILESYSTEM_SNAP_DETAILS = [ + { + "access_policy": None, + "access_policy_l10n": None, + "access_type": "Snapshot", + "access_type_l10n": "Snapshot", + "creation_timestamp": "2022-01-17T00:58:00+00:00", + "creator_type": "User", + "creator_type_l10n": "User", + "default_hard_limit": None, + "default_soft_limit": None, + "description": None, + "expiration_timestamp": "2022-01-17T00:58:00+00:00", + "filesystem_type": "Snapshot", + "filesystem_type_l10n": "Snapshot", + "folder_rename_policy": None, + "folder_rename_policy_l10n": None, + "grace_period": None, + "id": "61e49f3f-9b57-e69b-1038-aa02b52a030f", + "is_async_MTime_enabled": False, + "is_modified": False, + "is_quota_enabled": None, + "is_smb_no_notify_enabled": None, + "is_smb_notify_on_access_enabled": None, + "is_smb_notify_on_write_enabled": None, + "is_smb_op_locks_enabled": None, + "is_smb_sync_writes_enabled": None, + "last_refresh_timestamp": None, + "last_writable_timestamp": None, + "locking_policy": None, + "locking_policy_l10n": None, + "name": "Sample_FS_Snapshot", + "nas_server": { + "id": "6026056b-5405-0e36-7697-c285b9fa42b7", + "name": "ansible_nas_server_2" + }, + "parent_id": "61e4947b-8992-3db7-2859-aa02b52a0308", + "parent_name": "sample-filesystem", + "protection_policy": None, + "size_total": "214748364800", + "size_used": "1621098496", + "smb_notify_on_change_dir_depth": 0 + } + ] + MODIFY_FS_DETAILS = [{ "access_policy": "Native", "access_policy_l10n": "Native", @@ -258,3 +309,31 @@ def create_filesystem_with_size_less_than_3_failed_msg(): @staticmethod def create_filesystem_without_size_failed_msg(): return "cap_unit can be specified along with size" + + @staticmethod + def filesystem_with_invalid_default_hard_limit(): + return "default_hard_limit cannot be less than '0'" + + @staticmethod + def exception_messages(action_type): + if action_type == "modify_filesystem": + return 'Failed to modify filesystem id 621fb793-5e18-b998-462d-a6cb1f6ffcd6 with error ' + elif action_type == "delete_filesystem": + return 'Failed to delete filesystem id 621fb793-5e18-b998-462d-a6cb1f6ffcd6 with error ' + elif action_type == "create_filesystem": + return 'Create FileSystem with name sample_filesystem on powerstore array name : WN-ABCD , global id : 0 failed with error ' + elif action_type == "get_nas_server": + return 'Get NAS Server 6026056b-5405-0e36-7697-c285b9fa42b7 for powerstore array name : WN-ABCD , global id : 0 failed with error ' + elif action_type == "get_protection_policy": + return 'Get details of protection policy name or ID : 4db27abe-08cf-427d-a95b-e7a51216b0cf failed with error : ' + elif action_type == "get_filesystem_no_nas": + return "Get NAS Server 6026056b-5405-0e36-7697-c285b9fa42b7 for powerstore array name : WN-ABCD , global id : 0 failed with error" \ + " Failed to get NAS Server with id or name 6026056b-5405-0e36-7697-c285b9fa42b7 from powerstore system " + elif action_type == "fs_snapshot": + return "Failed to get filesystem snapshot" + elif action_type == "clone_filesystem": + return "Cloning filesystem failed with error" + elif action_type == "refresh_filesystem": + return "Refreshing filesystem failed with error" + elif action_type == "restore_filesystem": + return "Restoring filesystem failed with error" diff --git a/tests/unit/plugins/module_utils/mock_info_api.py b/tests/unit/plugins/module_utils/mock_info_api.py index 0c5d728..ec3f68d 100644 --- a/tests/unit/plugins/module_utils/mock_info_api.py +++ b/tests/unit/plugins/module_utils/mock_info_api.py @@ -39,11 +39,14 @@ class MockInfoApi: CLUSTER_DETAILS_TWO = [ { "id": "0", - "name": "WN-ABCD"}, + "name": "WN-ABCD", + "state": "Configured" + }, { "id": "1", - "name": "WN-WXYZ"} - + "name": "WN-WXYZ", + "state": "Configured" + } ] @staticmethod @@ -143,3 +146,7 @@ def get_no_gather_subset_failed_msg(): @staticmethod def get_subset_invalid_filter(): return "Filter should have all keys: 'filter_key, filter_operator, filter_value'" + + @staticmethod + def get_invalid_filter_key(): + return "Filter keys: '['filter_key', 'filter_operator', 'filter_value']' cannot be None" diff --git a/tests/unit/plugins/module_utils/mock_nasserver_api.py b/tests/unit/plugins/module_utils/mock_nasserver_api.py index 4eaaeeb..0d6edb9 100644 --- a/tests/unit/plugins/module_utils/mock_nasserver_api.py +++ b/tests/unit/plugins/module_utils/mock_nasserver_api.py @@ -27,7 +27,7 @@ class MockNasServerApi: 'protection_policy': None } NAS_SERVER_NAME_1 = "Sample_nas_server_1" - + NAS_SERVER_ID = "60c0564a-4a6e-04b6-4d5e-fe8be1eb93c9" PROTECTION_POLICY_DETAILS = [{ "description": None, "id": "bce845ea-78ba-4414-ada1-8130f3a49e74", @@ -40,6 +40,11 @@ class MockNasServerApi: "type": "Protection" }] + CLUSTERS = [{ + "id": "bce845ea-78ba-4414-ada1-8130f3a49e74", + "name": "cluster_1", + }] + NAS_SERVER_DETAILS = [{ "backup_IPv4_interface_id": None, "backup_IPv6_interface_id": None, @@ -184,8 +189,12 @@ class MockNasServerApi: @staticmethod def create_nas_server_failed_msg(): - return "Creation of NAS Server is not currently supported through Ansible Module" + return "Creating NAS server " + MockNasServerApi.NAS_SERVER_NAME_1 + " failed with error " + + @staticmethod + def modify_nas_server_failed_msg(): + return "Failed to modify nasserver" @staticmethod def delete_nas_server_failed_msg(): - return "Deletion of NAS Server is not currently supported through Ansible Module" + return "Deleting NAS server " + MockNasServerApi.NAS_SERVER_ID + " failed with error" diff --git a/tests/unit/plugins/module_utils/shared_library/__init__.py b/tests/unit/plugins/module_utils/shared_library/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/plugins/module_utils/mock_fail_json.py b/tests/unit/plugins/module_utils/shared_library/fail_json.py similarity index 100% rename from tests/unit/plugins/module_utils/mock_fail_json.py rename to tests/unit/plugins/module_utils/shared_library/fail_json.py diff --git a/tests/unit/plugins/module_utils/shared_library/initial_mock.py b/tests/unit/plugins/module_utils/shared_library/initial_mock.py new file mode 100644 index 0000000..8dea7cb --- /dev/null +++ b/tests/unit/plugins/module_utils/shared_library/initial_mock.py @@ -0,0 +1,16 @@ +# Copyright: (c) 2023, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type +from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ + import utils +from mock.mock import MagicMock + +utils.get_logger = MagicMock() +utils.get_powerstore_connection = MagicMock() +utils.PowerStoreException = MagicMock() +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() diff --git a/tests/unit/plugins/module_utils/shared_library/powerstore_unit_base.py b/tests/unit/plugins/module_utils/shared_library/powerstore_unit_base.py new file mode 100644 index 0000000..e8ee738 --- /dev/null +++ b/tests/unit/plugins/module_utils/shared_library/powerstore_unit_base.py @@ -0,0 +1,41 @@ +# Copyright: (c) 2023, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ + import MockApiException +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library. \ + fail_json import FailJsonException, fail_json + + +class PowerStoreUnitBase: + + '''Powerstore Unit Test Base Class''' + + @pytest.fixture + def powerstore_module_mock(self, mocker, module_object): + exception_class_path = 'ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell.utils.PowerStoreException' + mocker.patch(exception_class_path, new=MockApiException) + powerstore_module_mock = module_object() + powerstore_module_mock.module = MagicMock() + powerstore_module_mock.module.fail_json = fail_json + return powerstore_module_mock + + def capture_fail_json_call(self, error_msg, module_mock, module_handler=None, invoke_perform_module=False): + try: + if not invoke_perform_module: + module_handler().handle(module_mock, module_mock.module.params) + else: + module_mock.perform_module_operation() + except FailJsonException as fj_object: + if error_msg not in fj_object.message: + raise AssertionError(fj_object.message) + + def set_module_params(self, module_mock, get_module_args, params): + get_module_args.update(params) + module_mock.module.params = get_module_args diff --git a/tests/unit/plugins/modules/test_certificate.py b/tests/unit/plugins/modules/test_certificate.py index 10500d6..eb9bb0a 100644 --- a/tests/unit/plugins/modules/test_certificate.py +++ b/tests/unit/plugins/modules/test_certificate.py @@ -10,20 +10,14 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_certificate_api import MockCertificateApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_sdk_response \ import MockSDKResponse from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.certificate import PowerStoreCertificate diff --git a/tests/unit/plugins/modules/test_cluster.py b/tests/unit/plugins/modules/test_cluster.py index 8b84264..15bd051 100644 --- a/tests/unit/plugins/modules/test_cluster.py +++ b/tests/unit/plugins/modules/test_cluster.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_cluster_api import MockClusterApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.cluster import PowerStoreCluster diff --git a/tests/unit/plugins/modules/test_dns.py b/tests/unit/plugins/modules/test_dns.py index 1bd4951..f48f159 100644 --- a/tests/unit/plugins/modules/test_dns.py +++ b/tests/unit/plugins/modules/test_dns.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_dns_api import MockDnsApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.dns import PowerstoreDns diff --git a/tests/unit/plugins/modules/test_email.py b/tests/unit/plugins/modules/test_email.py index 959e4cc..f49107b 100644 --- a/tests/unit/plugins/modules/test_email.py +++ b/tests/unit/plugins/modules/test_email.py @@ -10,20 +10,14 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_email_api import MockEmailApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_sdk_response \ import MockSDKResponse from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.email import PowerstoreEmail diff --git a/tests/unit/plugins/modules/test_filesystem.py b/tests/unit/plugins/modules/test_filesystem.py index 300c2e3..2ac32b0 100644 --- a/tests/unit/plugins/modules/test_filesystem.py +++ b/tests/unit/plugins/modules/test_filesystem.py @@ -8,412 +8,564 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_filesystem_api import MockFilesystemApi +from ansible_collections.dellemc.powerstore.plugins.modules.filesystem import PowerStoreFileSystem from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() -from ansible_collections.dellemc.powerstore.plugins.modules.filesystem import PowerStoreFileSystem +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library.powerstore_unit_base \ + import PowerStoreUnitBase -class TestPowerStoreFileSystem(): +class TestPowerStoreFileSystem(PowerStoreUnitBase): get_module_args = MockFilesystemApi.FILESYSTEM_COMMON_ARGS @pytest.fixture - def filesystem_module_mock(self, mocker): - mocker.patch(MockFilesystemApi.MODULE_UTILS_PATH + '.PowerStoreException', new=MockApiException) - filesystem_module_mock = PowerStoreFileSystem() - filesystem_module_mock.module = MagicMock() - return filesystem_module_mock - - def test_get_filesystem_by_id(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_id": MockFilesystemApi.FS_ID, - "state": "present" - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_cluster_list = MagicMock( + def module_object(self): + return PowerStoreFileSystem + + def set_cluster(self, powerstore_module_mock): + powerstore_module_mock.provisioning.get_cluster_list = MagicMock( return_value=MockFilesystemApi.CLUSTER_DETAILS) - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + return powerstore_module_mock + + def test_get_filesystem_by_id(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_id": MockFilesystemApi.FS_ID, + "state": "present"}) + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.perform_module_operation() - assert self.get_module_args['filesystem_id'] == filesystem_module_mock.module.exit_json.call_args[1]["filesystem_details"]["id"] - filesystem_module_mock.provisioning.get_filesystem_details.assert_called() - - def test_get_filesystem_by_name(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_NAME, - "state": "present" - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_by_name = MagicMock( + powerstore_module_mock.perform_module_operation() + assert self.get_module_args['filesystem_id'] == powerstore_module_mock.module.exit_json.call_args[1]["filesystem_details"]["id"] + powerstore_module_mock.provisioning.get_filesystem_details.assert_called() + + def test_get_filesystem_by_name(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_NAME, + "state": "present"}) + powerstore_module_mock.provisioning.get_nas_server_by_name = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1) - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.perform_module_operation() - assert self.get_module_args["filesystem_name"] == filesystem_module_mock.module.exit_json.call_args[1]["filesystem_details"]["name"] - filesystem_module_mock.provisioning.get_filesystem_by_name.assert_called() + powerstore_module_mock.perform_module_operation() + assert self.get_module_args["filesystem_name"] == powerstore_module_mock.module.exit_json.call_args[1]["filesystem_details"]["name"] + powerstore_module_mock.provisioning.get_filesystem_by_name.assert_called() - def test_get_filesystem_with_exception(self, filesystem_module_mock): + def test_get_filesystem_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) MockApiException.HTTP_ERR = "1" MockApiException.err_code = "1" MockApiException.status_code = "404" - self.get_module_args.update({ - "filesystem_name": 'sample_filesystem', - "nas_server": MockFilesystemApi.NAS_ID, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_details = MagicMock( + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": 'sample_filesystem', + "nas_server": MockFilesystemApi.NAS_ID, + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_details = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS[0]) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( side_effect=MockApiException) - filesystem_module_mock.perform_module_operation() - filesystem_module_mock.provisioning.get_filesystem_by_name.assert_called() + powerstore_module_mock.perform_module_operation() + powerstore_module_mock.provisioning.get_filesystem_by_name.assert_called() - def test_get_filesystem_no_nas_exception(self, filesystem_module_mock): + def test_get_filesystem_no_nas_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) MockApiException.HTTP_ERR = "1" MockApiException.err_code = "1" MockApiException.status_code = "404" - self.get_module_args.update({ - "filesystem_name": 'sample_filesystem', - "nas_server": MockFilesystemApi.NAS_ID, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_details = MagicMock( + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": 'sample_filesystem', + "nas_server": MockFilesystemApi.NAS_ID, + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_details = MagicMock( return_value=None) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( side_effect=MockApiException) - filesystem_module_mock.perform_module_operation() - filesystem_module_mock.provisioning.get_nas_server_details.assert_called() + self.capture_fail_json_call(MockFilesystemApi.exception_messages("get_filesystem_no_nas"), + powerstore_module_mock, + invoke_perform_module=True) - def test_get_nas_for_filesystem_with_exception(self, filesystem_module_mock): + def test_get_nas_for_filesystem_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) MockApiException.HTTP_ERR = "1" MockApiException.err_code = "1" MockApiException.status_code = "404" - self.get_module_args.update({ - "filesystem_name": 'sample_filesystem', - "nas_server": MockFilesystemApi.NAS_ID, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_details = MagicMock( + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": 'sample_filesystem', + "nas_server": MockFilesystemApi.NAS_ID, + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_details = MagicMock( side_effect=MockApiException) - filesystem_module_mock.perform_module_operation() - filesystem_module_mock.provisioning.get_nas_server_details.assert_called() - - def test_create_filesystem(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_NAME, - 'description': MockFilesystemApi.DESCRIPTION1, - "size": 10, - "cap_unit": "GB", - "access_policy": "UNIX", - "locking_policy": "ADVISORY", - "folder_rename_policy": "ALL_FORBIDDEN", - "protection_policy": "sample_protection_policy", - "smb_properties": {"is_smb_notify_on_write_enabled": True, "is_smb_notify_on_access_enabled": True, - "is_smb_op_locks_enabled": True, "is_smb_no_notify_enabled": True, - "smb_notify_on_change_dir_depth": 1, "is_smb_sync_writes_enabled": True}, - "quota_defaults": {"grace_period": 1, "grace_period_unit": "months", - "default_hard_limit": 10, "default_soft_limit": 8, "cap_unit": None}, - "config_type": "General", - "is_async_mtime_enabled": True, - "flr_attributes": {"mode": "Enterprise", "minimum_retention": "5D", "maximum_retention": "10D", "default_retention": "7D"}, - "file_events_publishing_mode": True, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_by_name = MagicMock( + self.capture_fail_json_call(MockFilesystemApi.exception_messages("get_nas_server"), + powerstore_module_mock, + invoke_perform_module=True) + + def test_create_filesystem(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_NAME, + 'description': MockFilesystemApi.DESCRIPTION1, + "size": 10, + "cap_unit": "GB", + "access_policy": "UNIX", + "locking_policy": "ADVISORY", + "config_type": "GENERAL", + "folder_rename_policy": "ALL_FORBIDDEN", + "protection_policy": "sample_protection_policy", + "smb_properties": {"is_smb_notify_on_write_enabled": True, + "is_smb_notify_on_access_enabled": True, + "is_smb_op_locks_enabled": True, + "is_smb_no_notify_enabled": True, + "smb_notify_on_change_dir_depth": 1, + "is_smb_sync_writes_enabled": True}, + "quota_defaults": {"grace_period": 1, "grace_period_unit": "months", + "default_hard_limit": 10, + "default_soft_limit": 8, "cap_unit": None}, + "is_async_mtime_enabled": True, + "flr_attributes": {"mode": "Enterprise", + "minimum_retention": "5D", + "maximum_retention": "10D", + "default_retention": "7D"}, + "file_events_publishing_mode": "ALL", + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_by_name = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS) - filesystem_module_mock.protection.get_protection_policy_by_name = MagicMock( + powerstore_module_mock.protection.get_protection_policy_by_name = MagicMock( return_value=MockFilesystemApi.PROTECTION_POLICY_DETAILS) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=None) - filesystem_module_mock.provisioning.create_filesystem = MagicMock( + powerstore_module_mock.provisioning.create_filesystem = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.perform_module_operation() - assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True - filesystem_module_mock.provisioning.create_filesystem.assert_called() - - def test_create_filesystem_with_pp_id(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_NAME, - 'description': MockFilesystemApi.DESCRIPTION1, - "size": 10, - "cap_unit": "GB", - "access_policy": "UNIX", - "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_by_name = MagicMock( + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.create_filesystem.assert_called() + + def test_create_filesystem_with_pp_id(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_NAME, + 'description': MockFilesystemApi.DESCRIPTION1, + "size": 10, + "cap_unit": "GB", + "access_policy": "UNIX", + "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_by_name = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS) - filesystem_module_mock.protection.get_protection_policy_details = MagicMock( + powerstore_module_mock.protection.get_protection_policy_details = MagicMock( return_value=MockFilesystemApi.PROTECTION_POLICY_DETAILS[0]) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=None) - filesystem_module_mock.provisioning.create_filesystem = MagicMock( + powerstore_module_mock.provisioning.create_filesystem = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.perform_module_operation() - assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True - filesystem_module_mock.provisioning.create_filesystem.assert_called() + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.create_filesystem.assert_called() - def test_get_pp_to_create_filesystem_with_exception(self, filesystem_module_mock): + def test_get_pp_to_create_filesystem_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) MockApiException.HTTP_ERR = "1" MockApiException.err_code = "1" MockApiException.status_code = "404" - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_NAME, - "size": 10, - "cap_unit": "GB", - "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_by_name = MagicMock( + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_NAME, + "size": 10, + "cap_unit": "GB", + "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_by_name = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS) - filesystem_module_mock.protection.get_protection_policy_details = MagicMock( + powerstore_module_mock.protection.get_protection_policy_details = MagicMock( side_effect=MockApiException) - filesystem_module_mock.perform_module_operation() - filesystem_module_mock.protection.get_protection_policy_details.assert_called() + self.capture_fail_json_call(MockFilesystemApi.exception_messages("get_protection_policy"), + powerstore_module_mock, + invoke_perform_module=True) - def test_create_filesystem_with_exception(self, filesystem_module_mock): + def test_create_filesystem_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) MockApiException.HTTP_ERR = "1" MockApiException.err_code = "1" MockApiException.status_code = "400" - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_NAME, - "size": 10, - "cap_unit": "GB", - "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_by_name = MagicMock( + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_NAME, + "size": 10, + "cap_unit": "GB", + "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_by_name = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS) - filesystem_module_mock.protection.get_protection_policy_details = MagicMock( + powerstore_module_mock.protection.get_protection_policy_details = MagicMock( return_value=MockFilesystemApi.PROTECTION_POLICY_DETAILS[0]) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=None) - filesystem_module_mock.provisioning.create_filesystem = MagicMock( + powerstore_module_mock.provisioning.create_filesystem = MagicMock( side_effect=MockApiException) - filesystem_module_mock.perform_module_operation() - filesystem_module_mock.provisioning.create_filesystem.assert_called() - - def test_create_volume_with_size_less_than_3gb(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_NAME, - "size": 1, - "cap_unit": "GB", - "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.perform_module_operation() - assert MockFilesystemApi.create_filesystem_with_size_less_than_3_failed_msg() in \ - filesystem_module_mock.module.fail_json.call_args[1]['msg'] - - def test_create_volume_without_size(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_NAME, - "cap_unit": "GB", - "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.perform_module_operation() - assert MockFilesystemApi.create_filesystem_without_size_failed_msg() in \ - filesystem_module_mock.module.fail_json.call_args[1]['msg'] - - def test_modify_filesystem(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_NAME, - 'description': "", - "size": 4, - "cap_unit": "TB", - "access_policy": "NATIVE", - "locking_policy": "MANDATORY", - "folder_rename_policy": "SMB_FORBIDDEN", - "protection_policy": "", - "smb_properties": {"is_smb_notify_on_write_enabled": False, "is_smb_notify_on_access_enabled": False, - "is_smb_op_locks_enabled": False, "is_smb_no_notify_enabled": False, - "smb_notify_on_change_dir_depth": 3, "is_smb_sync_writes_enabled": False}, - "quota_defaults": {"grace_period": 2, "grace_period_unit": "weeks", - "default_hard_limit": 3, "default_soft_limit": 2, "cap_unit": "TB"}, - "is_async_mtime_enabled": True, - "flr_attributes": {"minimum_retention": "10D", "maximum_retention": "30D", "default_retention": "15D"}, - "file_events_publishing_mode": True, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_by_name = MagicMock( + self.capture_fail_json_call(MockFilesystemApi.exception_messages("create_filesystem"), + powerstore_module_mock, + invoke_perform_module=True) + + def test_create_volume_with_size_less_than_3gb(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_NAME, + "size": 1, + "cap_unit": "GB", + "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", + "state": 'present'}) + self.capture_fail_json_call(MockFilesystemApi.create_filesystem_with_size_less_than_3_failed_msg(), + powerstore_module_mock, + invoke_perform_module=True) + + def test_create_volume_without_size(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_NAME, + "cap_unit": "GB", + "protection_policy": "4db27abe-08cf-427d-a95b-e7a51216b0cf", + "state": 'present'}) + self.capture_fail_json_call(MockFilesystemApi.create_filesystem_without_size_failed_msg(), + powerstore_module_mock, + invoke_perform_module=True) + + def test_modify_filesystem(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_NAME, + 'description': "", + "size": 4, + "cap_unit": "TB", + "config_type": "GENERAL", + "access_policy": "NATIVE", + "locking_policy": "MANDATORY", + "folder_rename_policy": "SMB_FORBIDDEN", + "protection_policy": "", + "smb_properties": {"is_smb_notify_on_write_enabled": False, + "is_smb_notify_on_access_enabled": False, + "is_smb_op_locks_enabled": False, + "is_smb_no_notify_enabled": False, + "smb_notify_on_change_dir_depth": 3, + "is_smb_sync_writes_enabled": False}, + "quota_defaults": {"grace_period": 2, + "grace_period_unit": "weeks", + "default_hard_limit": 3, + "default_soft_limit": 2, + "cap_unit": "TB"}, + "is_async_mtime_enabled": True, + "flr_attributes": {"minimum_retention": "10D", + "maximum_retention": "30D", + "default_retention": "15D"}, + "file_events_publishing_mode": "ALL", + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_by_name = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1) - filesystem_module_mock.provisioning.modify_filesystem = MagicMock( + powerstore_module_mock.provisioning.modify_filesystem = MagicMock( return_value=None) - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.MODIFY_FS_DETAILS[0]) - filesystem_module_mock.perform_module_operation() - assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True - filesystem_module_mock.provisioning.modify_filesystem.assert_called() - - def test_modify_grace_period_to_days_filesystem(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_ID, - "size": 4, - "quota_defaults": {"grace_period": 2, "grace_period_unit": "days", - "default_hard_limit": 3, "default_soft_limit": 2, "cap_unit": "GB"}, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_details = MagicMock( + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.modify_filesystem.assert_called() + + def test_modify_grace_period_to_days_filesystem(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_ID, + "size": 4, + "quota_defaults": {"grace_period": 2, + "grace_period_unit": "days", + "default_hard_limit": 3, + "default_soft_limit": 2, + "cap_unit": "GB"}, + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_details = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS[0]) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=MockFilesystemApi.MODIFY_FS_DETAILS) - filesystem_module_mock.provisioning.modify_filesystem = MagicMock( + powerstore_module_mock.provisioning.modify_filesystem = MagicMock( return_value=None) - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.perform_module_operation() - assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True - filesystem_module_mock.provisioning.modify_filesystem.assert_called() - - def test_modify_grace_period_to_months_filesystem(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_ID, - "quota_defaults": {"grace_period": 5, "grace_period_unit": "months", - "default_hard_limit": 3, "default_soft_limit": 2, "cap_unit": "GB"}, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_details = MagicMock( + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.modify_filesystem.assert_called() + + def test_modify_grace_period_to_months_filesystem(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_ID, + "quota_defaults": {"grace_period": 5, + "grace_period_unit": "months", + "default_hard_limit": 3, + "default_soft_limit": 2, + "cap_unit": "GB"}, + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_details = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS[0]) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=MockFilesystemApi.MODIFY_FS_DETAILS) - filesystem_module_mock.provisioning.modify_filesystem = MagicMock( + powerstore_module_mock.provisioning.modify_filesystem = MagicMock( return_value=None) - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.perform_module_operation() - assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True - filesystem_module_mock.provisioning.modify_filesystem.assert_called() - - def test_modify_filesystem_wo_grace_period_unit_wo_cap_unit(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_ID, - "quota_defaults": {"grace_period": 5, "grace_period_unit": None, - "default_hard_limit": 3, "default_soft_limit": 2, "cap_unit": None}, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_details = MagicMock( + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.modify_filesystem.assert_called() + + def test_modify_filesystem_wo_grace_period_unit_wo_cap_unit(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_ID, + "quota_defaults": {"grace_period": 5, + "grace_period_unit": None, + "default_hard_limit": 3, + "default_soft_limit": 2, + "cap_unit": None}, + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_details = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS[0]) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=MockFilesystemApi.MODIFY_FS_DETAILS) - filesystem_module_mock.provisioning.modify_filesystem = MagicMock( + powerstore_module_mock.provisioning.modify_filesystem = MagicMock( return_value=None) - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.perform_module_operation() - assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True - filesystem_module_mock.provisioning.modify_filesystem.assert_called() + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.modify_filesystem.assert_called() - def test_modify_filesystem_with_exception(self, filesystem_module_mock): + def test_modify_filesystem_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) MockApiException.HTTP_ERR = "1" MockApiException.err_code = "1" MockApiException.status_code = "400" - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_ID, - "size": 4, - "quota_defaults": {"grace_period": 2, "grace_period_unit": "days", - "default_hard_limit": 3, "default_soft_limit": 2, "cap_unit": "GB"}, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_details = MagicMock( + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_ID, + "size": 4, + "quota_defaults": {"grace_period": 2, + "grace_period_unit": "days", + "default_hard_limit": 3, + "default_soft_limit": 2, + "cap_unit": "GB"}, + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_details = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS[0]) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=MockFilesystemApi.MODIFY_FS_DETAILS) - filesystem_module_mock.provisioning.modify_filesystem = MagicMock( + powerstore_module_mock.provisioning.modify_filesystem = MagicMock( side_effect=MockApiException) - filesystem_module_mock.perform_module_operation() - filesystem_module_mock.provisioning.modify_filesystem.assert_called() + self.capture_fail_json_call(MockFilesystemApi.exception_messages("modify_filesystem"), + powerstore_module_mock, + invoke_perform_module=True) - def test_modify_filesystem_with_invalid_default_hard_limit(self, filesystem_module_mock): + def test_modify_filesystem_with_invalid_default_hard_limit(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) MockApiException.HTTP_ERR = "1" MockApiException.err_code = "1" MockApiException.status_code = "400" - self.get_module_args.update({ - "filesystem_name": MockFilesystemApi.FS_NAME, - "nas_server": MockFilesystemApi.NAS_ID, - "size": 4, - "quota_defaults": {"grace_period": 2, "grace_period_unit": "days", - "default_hard_limit": -1, "default_soft_limit": 2, "cap_unit": "GB"}, - "state": 'present' - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_nas_server_details = MagicMock( + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_name": MockFilesystemApi.FS_NAME, + "nas_server": MockFilesystemApi.NAS_ID, + "size": 4, + "quota_defaults": {"grace_period": 2, + "grace_period_unit": "days", + "default_hard_limit": -1, + "default_soft_limit": 2, + "cap_unit": "GB"}, + "state": 'present'}) + powerstore_module_mock.provisioning.get_nas_server_details = MagicMock( return_value=MockFilesystemApi.NAS_SERVER_DETAILS[0]) - filesystem_module_mock.provisioning.get_filesystem_by_name = MagicMock( + powerstore_module_mock.provisioning.get_filesystem_by_name = MagicMock( return_value=MockFilesystemApi.MODIFY_FS_DETAILS) - filesystem_module_mock.provisioning.modify_filesystem = MagicMock( + powerstore_module_mock.provisioning.modify_filesystem = MagicMock( side_effect=MockApiException) - filesystem_module_mock.perform_module_operation() - filesystem_module_mock.provisioning.modify_filesystem.assert_called() - - def test_delete_filesystem(self, filesystem_module_mock): - self.get_module_args.update({ - "filesystem_id": MockFilesystemApi.FS_ID, - "state": "absent" - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + self.capture_fail_json_call(MockFilesystemApi.filesystem_with_invalid_default_hard_limit(), + powerstore_module_mock, + invoke_perform_module=True) + + def test_delete_filesystem(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_id": MockFilesystemApi.FS_ID, + "state": "absent"}) + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.perform_module_operation() - assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True - filesystem_module_mock.provisioning.delete_filesystem.assert_called() + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.delete_filesystem.assert_called() - def test_delete_filesystem_with_exception(self, filesystem_module_mock): + def test_delete_filesystem_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) MockApiException.HTTP_ERR = "1" MockApiException.err_code = "1" MockApiException.status_code = "400" - self.get_module_args.update({ - "filesystem_id": MockFilesystemApi.FS_ID, - "state": "absent" - }) - filesystem_module_mock.module.params = self.get_module_args - filesystem_module_mock.provisioning.get_filesystem_details = MagicMock( + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_id": MockFilesystemApi.FS_ID, + "state": "absent"}) + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( return_value=MockFilesystemApi.FS_DETAILS_1[0]) - filesystem_module_mock.provisioning.delete_filesystem = MagicMock( + powerstore_module_mock.provisioning.delete_filesystem = MagicMock( side_effect=MockApiException) - filesystem_module_mock.perform_module_operation() - filesystem_module_mock.provisioning.delete_filesystem.assert_called() + self.capture_fail_json_call(MockFilesystemApi.exception_messages("delete_filesystem"), + powerstore_module_mock, + invoke_perform_module=True) + + def test_get_filesystem_snapshot(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {'snapshot_id': "61e49f3f-9b57-e69b-1038-aa02b52a030f", + 'refresh_filesystem': True, + 'state': "present"}) + powerstore_module_mock.module.params = self.get_module_args + powerstore_module_mock.protection.get_filesystem_snapshot_details = MagicMock( + return_value=MockFilesystemApi.FILESYSTEM_SNAP_DETAILS[0]) + assert powerstore_module_mock.provisioning.get_filesystem_snapshot_details() + powerstore_module_mock.provisioning.get_filesystem_snapshot_details.assert_called() + + def test_get_filesystem_snapshot_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {'snapshot_id': "61e49f3f-9b57-e69b-1038-aa02b52a030f", + 'refresh_filesystem': True, + 'state': "present"}) + powerstore_module_mock.module.params = self.get_module_args + powerstore_module_mock.protection.get_filesystem_snapshot_details = MagicMock(side_effect=MockApiException) + self.capture_fail_json_call(MockFilesystemApi.exception_messages("fs_snapshot"), + powerstore_module_mock, + invoke_perform_module=True) + + def test_clone_filesystem(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_id": MockFilesystemApi.FS_ID, + "clone_filesystem": {"name": "Test"}, + "state": 'present'}) + powerstore_module_mock.module.params = self.get_module_args + powerstore_module_mock.set_parms = MagicMock(side_effect=[None, None, MockFilesystemApi.FS_DETAILS_1[0]]) + powerstore_module_mock.get_filesystem_details = MagicMock() + powerstore_module_mock.get_clone = MagicMock(return_value=None) + powerstore_module_mock.clone_filesystem_dict_params = MagicMock(return_value={"name": "Test"}) + powerstore_module_mock.provisioning.clone_filesystem = MagicMock() + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.clone_filesystem.assert_called() + + def test_clone_filesystem_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"filesystem_id": MockFilesystemApi.FS_ID, + "clone_filesystem": {"name": "Test"}, + "state": 'present'}) + powerstore_module_mock.module.params = self.get_module_args + powerstore_module_mock.set_parms = MagicMock(side_effect=[None, None, MockFilesystemApi.FS_DETAILS_1[0]]) + powerstore_module_mock.get_filesystem_details = MagicMock() + powerstore_module_mock.get_clone = MagicMock(return_value=None) + powerstore_module_mock.clone_filesystem_dict_params = MagicMock(return_value={"name": "Test"}) + powerstore_module_mock.provisioning.clone_filesystem = MagicMock(side_effect=MockApiException) + self.capture_fail_json_call(MockFilesystemApi.exception_messages("clone_filesystem"), + powerstore_module_mock, + invoke_perform_module=True) + + def test_refresh_filesystem(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"snapshot_id": MockFilesystemApi.SNAP_ID, + "refresh_filesystem": True, + "state": 'present'}) + powerstore_module_mock.module.params = self.get_module_args + powerstore_module_mock.provisioning.refresh_filesystem = MagicMock( + return_value=None) + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( + return_value=MockFilesystemApi.FS_DETAILS_1[0]) + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.refresh_filesystem.assert_called() + + def test_refresh_filesystem_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"snapshot_id": MockFilesystemApi.SNAP_ID, + "refresh_filesystem": True, + "state": 'present'}) + powerstore_module_mock.module.params = self.get_module_args + powerstore_module_mock.provisioning.refresh_filesystem = MagicMock(side_effect=MockApiException) + self.capture_fail_json_call(MockFilesystemApi.exception_messages("refresh_filesystem"), + powerstore_module_mock, + invoke_perform_module=True) + + def test_restore_filesystem(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"snapshot_id": MockFilesystemApi.SNAP_ID, + "restore_filesystem": True, + "state": 'present'}) + powerstore_module_mock.module.params = self.get_module_args + powerstore_module_mock.provisioning.restore_filesystem = MagicMock( + return_value=None) + powerstore_module_mock.provisioning.get_filesystem_details = MagicMock( + return_value=MockFilesystemApi.FS_DETAILS_1[0]) + powerstore_module_mock.perform_module_operation() + assert powerstore_module_mock.module.exit_json.call_args[1]['changed'] is True + powerstore_module_mock.provisioning.restore_filesystem.assert_called() + + def test_restore_filesystem_with_exception(self, powerstore_module_mock): + powerstore_module_mock = self.set_cluster(powerstore_module_mock) + self.set_module_params(powerstore_module_mock, + self.get_module_args, + {"snapshot_id": MockFilesystemApi.SNAP_ID, + "restore_filesystem": True, + "state": 'present'}) + powerstore_module_mock.module.params = self.get_module_args + powerstore_module_mock.provisioning.restore_filesystem = MagicMock(side_effect=MockApiException) + self.capture_fail_json_call(MockFilesystemApi.exception_messages("restore_filesystem"), + powerstore_module_mock, + invoke_perform_module=True) diff --git a/tests/unit/plugins/modules/test_filesystem_snapshot.py b/tests/unit/plugins/modules/test_filesystem_snapshot.py index 9521d80..ee03717 100644 --- a/tests/unit/plugins/modules/test_filesystem_snapshot.py +++ b/tests/unit/plugins/modules/test_filesystem_snapshot.py @@ -9,18 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_filesystem_snapshot_api import MockFilesystemSnapshotApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.filesystem_snapshot import PowerStoreFilesystemSnapshot diff --git a/tests/unit/plugins/modules/test_host.py b/tests/unit/plugins/modules/test_host.py index 85ed1ae..27869b4 100644 --- a/tests/unit/plugins/modules/test_host.py +++ b/tests/unit/plugins/modules/test_host.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_host_api import MockHostApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.host import PowerStoreHost diff --git a/tests/unit/plugins/modules/test_hostgroup.py b/tests/unit/plugins/modules/test_hostgroup.py index 8db9bec..9235712 100644 --- a/tests/unit/plugins/modules/test_hostgroup.py +++ b/tests/unit/plugins/modules/test_hostgroup.py @@ -9,18 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_hostgroup_api import MockHostGroupApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.hostgroup import PowerStoreHostgroup diff --git a/tests/unit/plugins/modules/test_info.py b/tests/unit/plugins/modules/test_info.py index ae12585..d131af7 100644 --- a/tests/unit/plugins/modules/test_info.py +++ b/tests/unit/plugins/modules/test_info.py @@ -9,18 +9,13 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_info_api import MockInfoApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() + from ansible_collections.dellemc.powerstore.plugins.modules.info import PowerstoreInfo @@ -189,6 +184,8 @@ def test_get_role_get_array_version_exception(self, info_module_mock): 'all_pages': None }) info_module_mock.module.params = self.get_module_args + info_module_mock.provisioning.get_cluster_list = MagicMock( + return_value=MockInfoApi.CLUSTER_DETAILS_TWO) info_module_mock.provisioning.get_array_version = MagicMock( side_effect=MockApiException) info_module_mock.perform_module_operation() @@ -316,3 +313,29 @@ def test_get_replication_groups(self, info_module_mock): info_module_mock.module.params = self.get_module_args info_module_mock.perform_module_operation() info_module_mock.protection.get_replication_groups.assert_called() + + def test_get_discovered_appliances(self, info_module_mock): + self.get_module_args.update({ + 'gather_subset': ['discovered_appliance'], + 'filters': None, + 'all_pages': None + }) + info_module_mock.module.params = self.get_module_args + info_module_mock.perform_module_operation() + info_module_mock.configuration.get_discovered_appliances.assert_called() + + def test_get_filesystem_invalid_filter_key(self, info_module_mock): + self.get_module_args.update({ + 'gather_subset': ['file_system'], + 'filters': [{ + 'filter_key': 'access_type', + 'filter_operator': "equal", + 'filter_value': 'Snapshot', + 'filter_subset': None + }], + 'all_pages': None + }) + info_module_mock.module.params = self.get_module_args + info_module_mock.perform_module_operation() + assert MockInfoApi.get_invalid_filter_key() in \ + info_module_mock.module.fail_json.call_args[1]['msg'] diff --git a/tests/unit/plugins/modules/test_job.py b/tests/unit/plugins/modules/test_job.py index c9b4fb7..9bf3b8c 100644 --- a/tests/unit/plugins/modules/test_job.py +++ b/tests/unit/plugins/modules/test_job.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_job_api import MockJobApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.job import PowerStoreJob diff --git a/tests/unit/plugins/modules/test_ldap_account.py b/tests/unit/plugins/modules/test_ldap_account.py index f5bb00c..b42550d 100644 --- a/tests/unit/plugins/modules/test_ldap_account.py +++ b/tests/unit/plugins/modules/test_ldap_account.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_ldap_account_api import MockLDAPAccountApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.ldap_account import PowerStoreLDAPAccount diff --git a/tests/unit/plugins/modules/test_ldap_domain.py b/tests/unit/plugins/modules/test_ldap_domain.py index 0dddaed..b06a597 100644 --- a/tests/unit/plugins/modules/test_ldap_domain.py +++ b/tests/unit/plugins/modules/test_ldap_domain.py @@ -9,17 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_ldap_domain_api import MockLDAPDomainApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.ldap_domain import PowerStoreLDAPDomain diff --git a/tests/unit/plugins/modules/test_local_user.py b/tests/unit/plugins/modules/test_local_user.py index 69f4de6..d91ecea 100644 --- a/tests/unit/plugins/modules/test_local_user.py +++ b/tests/unit/plugins/modules/test_local_user.py @@ -9,18 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_local_user_api import MockLocalUserApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.local_user import PowerStoreLocalUser diff --git a/tests/unit/plugins/modules/test_nasserver.py b/tests/unit/plugins/modules/test_nasserver.py index 807b992..c8c1488 100644 --- a/tests/unit/plugins/modules/test_nasserver.py +++ b/tests/unit/plugins/modules/test_nasserver.py @@ -9,19 +9,15 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_nasserver_api import MockNasServerApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.nasserver import PowerStoreNasServer +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library.\ + fail_json import FailJsonException, fail_json class TestPowerstoreNasServer(): @@ -33,16 +29,19 @@ def nasserver_module_mock(self, mocker): mocker.patch(MockNasServerApi.MODULE_UTILS_PATH + '.PowerStoreException', new=MockApiException) nasserver_module_mock = PowerStoreNasServer() nasserver_module_mock.module = MagicMock() + nasserver_module_mock.get_clusters = MagicMock(return_value=MockNasServerApi.CLUSTERS) + nasserver_module_mock.module.fail_json = fail_json return nasserver_module_mock def test_get_nasserver_response(self, nasserver_module_mock): self.get_module_args.update({ - 'nas_server_id': "60c0564a-4a6e-04b6-4d5e-fe8be1eb93c9", + 'nas_server_id': MockNasServerApi.NAS_SERVER_ID, 'state': "present" }) nasserver_module_mock.module.params = self.get_module_args nasserver_module_mock.provisioning.get_nas_server_details = MagicMock( return_value=MockNasServerApi.NAS_SERVER_DETAILS[0]) + nasserver_module_mock.provisioning.get_nodes = MagicMock(return_value=MockNasServerApi.NODE_DETAILS) nasserver_module_mock.perform_module_operation() assert self.get_module_args['nas_server_id'] == nasserver_module_mock.module.exit_json.call_args[1]['nasserver_details']['id'] nasserver_module_mock.provisioning.get_nas_server_details.assert_called() @@ -53,8 +52,9 @@ def test_get_nasserver_name_response(self, nasserver_module_mock): 'state': "present" }) nasserver_module_mock.module.params = self.get_module_args - nasserver_module_mock.provisioning.get_nas_server_details = MagicMock( - return_value=MockNasServerApi.NAS_SERVER_DETAILS[0]) + nasserver_module_mock.provisioning.get_nas_server_by_name = MagicMock( + return_value=MockNasServerApi.NAS_SERVER_DETAILS) + nasserver_module_mock.provisioning.get_nodes = MagicMock(return_value=MockNasServerApi.NODE_DETAILS) nasserver_module_mock.perform_module_operation() assert self.get_module_args['nas_server_name'] == nasserver_module_mock.module.exit_json.call_args[1]['nasserver_details']['name'] nasserver_module_mock.provisioning.get_nas_server_by_name.assert_called() @@ -68,34 +68,11 @@ def test_get_nasserver_name_exception(self, nasserver_module_mock): 'state': "present" }) nasserver_module_mock.module.params = self.get_module_args + nasserver_module_mock.get_node_id = MagicMock() nasserver_module_mock.provisioning.get_nas_server_by_name = MagicMock( side_effect=MockApiException) nasserver_module_mock.perform_module_operation() - nasserver_module_mock.provisioning.get_nas_server_by_name.assert_called() - - def test_create_nasserver_name(self, nasserver_module_mock): - self.get_module_args.update({ - 'nas_server_name': "Sample_nas_server_1", - 'state': "present" - }) - nasserver_module_mock.module.params = self.get_module_args - nasserver_module_mock.provisioning.get_nas_server_by_name = MagicMock( - return_value=None) - nasserver_module_mock.perform_module_operation() - assert MockNasServerApi.create_nas_server_failed_msg() in \ - nasserver_module_mock.module.fail_json.call_args[1]['msg'] - - def test_delete_nasserver(self, nasserver_module_mock): - self.get_module_args.update({ - 'nas_server_name': "Sample_nas_server_1", - 'state': "absent" - }) - nasserver_module_mock.module.params = self.get_module_args - nasserver_module_mock.provisioning.get_nas_server_details = MagicMock( - return_value=MockNasServerApi.NAS_SERVER_DETAILS[0]) - nasserver_module_mock.perform_module_operation() - assert MockNasServerApi.delete_nas_server_failed_msg() in \ - nasserver_module_mock.module.fail_json.call_args[1]['msg'] + nasserver_module_mock.provisioning.create_nasserver.assert_called() def test_modify_nasserver_response(self, nasserver_module_mock): self.get_module_args.update({ @@ -186,12 +163,12 @@ def test_modify_nasserver_exception(self, nasserver_module_mock): return_value=MockNasServerApi.NODE_DETAILS) nasserver_module_mock.provisioning.modify_nasserver = MagicMock( side_effect=MockApiException) - nasserver_module_mock.perform_module_operation() - nasserver_module_mock.provisioning.modify_nasserver.assert_called() + self.capture_fail_json_call( + MockNasServerApi.modify_nas_server_failed_msg(), nasserver_module_mock) def test_get_nasserver_multi_cluster(self, nasserver_module_mock): self.get_module_args.update({ - 'nas_server_id': "60c0564a-4a6e-04b6-4d5e-fe8be1eb93c9", + 'nas_server_id': MockNasServerApi.NAS_SERVER_ID, 'state': "present" }) nasserver_module_mock.module.params = self.get_module_args @@ -199,6 +176,82 @@ def test_get_nasserver_multi_cluster(self, nasserver_module_mock): return_value=MockNasServerApi.NAS_SERVER_DETAILS[0]) nasserver_module_mock.provisioning.get_cluster_list = MagicMock( return_value=MockNasServerApi.CLUSTER_DETAILS) + nasserver_module_mock.provisioning.get_nodes = MagicMock( + return_value=MockNasServerApi.NODE_DETAILS) nasserver_module_mock.perform_module_operation() assert self.get_module_args['nas_server_id'] == nasserver_module_mock.module.exit_json.call_args[1]['nasserver_details']['id'] nasserver_module_mock.provisioning.get_nas_server_details.assert_called() + + def test_create_nas_server(self, nasserver_module_mock): + nasserver_module_mock.provisioning.get_nas_server_details = MagicMock( + return_value={}) + self.get_module_args.update({ + "name": "my-nas-server", + "description": "My NAS Server", + "current_unix_directory_service": "LDAP", + "default_unix_user": "nobody", + "default_windows_user": "Guest", + "is_username_translation_enabled": True, + "is_auto_user_mapping_enabled": True, + "protection_policy_id": "policy-id-123", + "state": "present" + }) + nasserver_module_mock.module.params = self.get_module_args + nasserver_module_mock.get_node_id = MagicMock() + nasserver_module_mock.provisioning.create_nasserver = MagicMock( + return_value={'id': 'nas_server_id'}) + nasserver_module_mock.perform_module_operation() + nasserver_module_mock.provisioning.create_nasserver.assert_called() + + def test_create_nasserver_exception(self, nasserver_module_mock): + nasserver_module_mock.provisioning.get_nas_server_details = MagicMock( + return_value={}) + self.get_module_args.update({ + "nas_server_name": MockNasServerApi.NAS_SERVER_NAME_1, + "description": "My NAS Server", + "current_unix_directory_service": "LDAP", + "default_unix_user": "nobody", + "default_windows_user": "Guest", + "is_username_translation_enabled": True, + "is_auto_user_mapping_enabled": True, + "protection_policy_id": "policy-id-123", + "state": "present" + }) + nasserver_module_mock.module.params = self.get_module_args + nasserver_module_mock.get_node_id = MagicMock() + nasserver_module_mock.provisioning.create_nasserver = MagicMock( + side_effect=MockApiException) + self.capture_fail_json_call( + MockNasServerApi.create_nas_server_failed_msg(), nasserver_module_mock) + + def test_delete_nas_server(self, nasserver_module_mock): + nasserver_module_mock.provisioning.get_nas_server_details = MagicMock( + return_value=MockNasServerApi.NAS_SERVER_DETAILS[0]) + self.get_module_args.update({ + 'nas_server_id': MockNasServerApi.NAS_SERVER_ID, + "state": "absent" + }) + nasserver_module_mock.module.params = self.get_module_args + nasserver_module_mock.provisioning.delete_nasserver = MagicMock(return_value=None) + nasserver_module_mock.perform_module_operation() + nasserver_module_mock.provisioning.delete_nasserver.assert_called_once_with( + MockNasServerApi.NAS_SERVER_ID) + + def test_delete_nas_server_exception(self, nasserver_module_mock): + nasserver_module_mock.provisioning.get_nas_server_details = MagicMock( + return_value=MockNasServerApi.NAS_SERVER_DETAILS[0]) + self.get_module_args.update({ + 'nas_server_id': MockNasServerApi.NAS_SERVER_ID, + "state": "absent" + }) + nasserver_module_mock.module.params = self.get_module_args + nasserver_module_mock.provisioning.delete_nasserver = MagicMock( + side_effect=MockApiException) + self.capture_fail_json_call( + MockNasServerApi.delete_nas_server_failed_msg(), nasserver_module_mock) + + def capture_fail_json_call(self, error_msg, nasserver_module_mock): + try: + nasserver_module_mock.perform_module_operation() + except FailJsonException as fj_object: + assert error_msg in fj_object.message diff --git a/tests/unit/plugins/modules/test_network.py b/tests/unit/plugins/modules/test_network.py index bf4c7ba..bbf203d 100644 --- a/tests/unit/plugins/modules/test_network.py +++ b/tests/unit/plugins/modules/test_network.py @@ -9,18 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_network_api import MockNetworkApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.network import PowerStoreNetwork diff --git a/tests/unit/plugins/modules/test_nfs.py b/tests/unit/plugins/modules/test_nfs.py index b11ed3e..05f1aef 100644 --- a/tests/unit/plugins/modules/test_nfs.py +++ b/tests/unit/plugins/modules/test_nfs.py @@ -9,18 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_nfs_api import MockNfsApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.nfs import PowerStoreNfsExport diff --git a/tests/unit/plugins/modules/test_ntp.py b/tests/unit/plugins/modules/test_ntp.py index 4bed8e7..49eee91 100644 --- a/tests/unit/plugins/modules/test_ntp.py +++ b/tests/unit/plugins/modules/test_ntp.py @@ -9,19 +9,13 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_ntp_api \ import MockNtpApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.ntp import PowerstoreNtp diff --git a/tests/unit/plugins/modules/test_protectionpolicy.py b/tests/unit/plugins/modules/test_protectionpolicy.py index 9ed44f0..ec1b691 100644 --- a/tests/unit/plugins/modules/test_protectionpolicy.py +++ b/tests/unit/plugins/modules/test_protectionpolicy.py @@ -9,18 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_protectionpolicy_api import MockProtectionpolicyApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.protectionpolicy import PowerstoreProtectionpolicy diff --git a/tests/unit/plugins/modules/test_quota.py b/tests/unit/plugins/modules/test_quota.py index 23d7fd3..08ea405 100644 --- a/tests/unit/plugins/modules/test_quota.py +++ b/tests/unit/plugins/modules/test_quota.py @@ -9,18 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_quota_api import MockQuotaApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.quota import PowerStoreQuota diff --git a/tests/unit/plugins/modules/test_remote_support.py b/tests/unit/plugins/modules/test_remote_support.py index 0645b06..d14f2f6 100644 --- a/tests/unit/plugins/modules/test_remote_support.py +++ b/tests/unit/plugins/modules/test_remote_support.py @@ -10,19 +10,13 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_remote_support_api \ import MockRemoteSupportApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.remote_support \ import PowerstoreRemoteSupport diff --git a/tests/unit/plugins/modules/test_remote_support_contact.py b/tests/unit/plugins/modules/test_remote_support_contact.py index 26e78e5..7163cad 100644 --- a/tests/unit/plugins/modules/test_remote_support_contact.py +++ b/tests/unit/plugins/modules/test_remote_support_contact.py @@ -10,19 +10,13 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_remote_support_contact_api \ import MockRemoteSupportContactApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.remote_support_contact \ import PowerstoreRemoteSupportContact diff --git a/tests/unit/plugins/modules/test_remotesystem.py b/tests/unit/plugins/modules/test_remotesystem.py index 2280b32..c5c41bd 100644 --- a/tests/unit/plugins/modules/test_remotesystem.py +++ b/tests/unit/plugins/modules/test_remotesystem.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_remotesystem_api import MockRemoteSystemApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.remotesystem import PowerstoreRemoteSystem diff --git a/tests/unit/plugins/modules/test_replicationrule.py b/tests/unit/plugins/modules/test_replicationrule.py index 09626b2..82d55d2 100644 --- a/tests/unit/plugins/modules/test_replicationrule.py +++ b/tests/unit/plugins/modules/test_replicationrule.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_replicationrule_api import MockReplicationRuleApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.replicationrule import PowerstoreReplicationRule diff --git a/tests/unit/plugins/modules/test_replicationsession.py b/tests/unit/plugins/modules/test_replicationsession.py index 03ad4bf..d9b238f 100644 --- a/tests/unit/plugins/modules/test_replicationsession.py +++ b/tests/unit/plugins/modules/test_replicationsession.py @@ -10,22 +10,16 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_replicationsession_api import MockReplicationSessionApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.replicationsession\ import PowerstoreReplicationSession -from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.\ - mock_fail_json import FailJsonException, fail_json +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library.\ + fail_json import FailJsonException, fail_json class TestPowerstoreReplicationSession(): diff --git a/tests/unit/plugins/modules/test_role.py b/tests/unit/plugins/modules/test_role.py index b8c6f88..5894387 100644 --- a/tests/unit/plugins/modules/test_role.py +++ b/tests/unit/plugins/modules/test_role.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_role_api import MockRoleApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.role import PowerStoreRole diff --git a/tests/unit/plugins/modules/test_security_config.py b/tests/unit/plugins/modules/test_security_config.py index 38c246d..162d0bd 100644 --- a/tests/unit/plugins/modules/test_security_config.py +++ b/tests/unit/plugins/modules/test_security_config.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_security_config_api import MockSecurityConfigApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.security_config import PowerStoreSecurityConfig diff --git a/tests/unit/plugins/modules/test_smbshare.py b/tests/unit/plugins/modules/test_smbshare.py index 6da0c7e..1124b36 100644 --- a/tests/unit/plugins/modules/test_smbshare.py +++ b/tests/unit/plugins/modules/test_smbshare.py @@ -9,18 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_smbshare_api import MockSMBShareApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.smbshare import PowerStoreSMBShare diff --git a/tests/unit/plugins/modules/test_smtp_config.py b/tests/unit/plugins/modules/test_smtp_config.py index 26f3923..0dfa2fe 100644 --- a/tests/unit/plugins/modules/test_smtp_config.py +++ b/tests/unit/plugins/modules/test_smtp_config.py @@ -10,18 +10,12 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_smtp_config_api import MockSmtpConfigApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.smtp_config import PowerstoreSmtpConfig diff --git a/tests/unit/plugins/modules/test_snapshot.py b/tests/unit/plugins/modules/test_snapshot.py index b83495f..aaa9517 100644 --- a/tests/unit/plugins/modules/test_snapshot.py +++ b/tests/unit/plugins/modules/test_snapshot.py @@ -9,18 +9,13 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.\ mock_snapshot_api import MockSnapshotApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.\ mock_api_exception import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.snapshot import PowerStoreSnapshot diff --git a/tests/unit/plugins/modules/test_snapshotrule.py b/tests/unit/plugins/modules/test_snapshotrule.py index 133c314..14ba3ac 100644 --- a/tests/unit/plugins/modules/test_snapshotrule.py +++ b/tests/unit/plugins/modules/test_snapshotrule.py @@ -9,18 +9,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_snapshotrule_api import MockSnapshotruleApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.snapshotrule import PowerstoreSnapshotrule diff --git a/tests/unit/plugins/modules/test_storage_container.py b/tests/unit/plugins/modules/test_storage_container.py index 3659c69..619f7af 100644 --- a/tests/unit/plugins/modules/test_storage_container.py +++ b/tests/unit/plugins/modules/test_storage_container.py @@ -10,6 +10,8 @@ import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_storage_container_api import MockStorageContainerApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ @@ -17,18 +19,15 @@ from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ import utils -utils.get_logger = MagicMock() remote_config = MagicMock() remote_config.config_mgmt.get_storage_container_details = MagicMock(return_value=MockStorageContainerApi.REMOTE_STORAGE_CONTAINER_1) utils.get_powerstore_connection = MagicMock(side_effect=[ MagicMock(), remote_config ]) -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.storage_container import PowerStoreStorageContainer, StorageContainerHandler -from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_fail_json import FailJsonException, fail_json +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library.\ + fail_json import FailJsonException, fail_json class TestPowerStoreStorageContainer(): diff --git a/tests/unit/plugins/modules/test_vcenter.py b/tests/unit/plugins/modules/test_vcenter.py index 09e5c48..cc0dc6a 100644 --- a/tests/unit/plugins/modules/test_vcenter.py +++ b/tests/unit/plugins/modules/test_vcenter.py @@ -8,18 +8,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_vcenter_api import MockVCenterApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.vcenter import PowerstoreVCenter diff --git a/tests/unit/plugins/modules/test_volume.py b/tests/unit/plugins/modules/test_volume.py index 9975337..f9a5270 100644 --- a/tests/unit/plugins/modules/test_volume.py +++ b/tests/unit/plugins/modules/test_volume.py @@ -8,18 +8,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_volume_api import MockVolumeApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.volume import PowerStoreVolume diff --git a/tests/unit/plugins/modules/test_volumegroup.py b/tests/unit/plugins/modules/test_volumegroup.py index 0a757ba..a7487cf 100644 --- a/tests/unit/plugins/modules/test_volumegroup.py +++ b/tests/unit/plugins/modules/test_volumegroup.py @@ -8,18 +8,12 @@ __metaclass__ = type import pytest +# pylint: disable=unused-import +from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.shared_library import initial_mock from mock.mock import MagicMock from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_volumegroup_api import MockVolumeGroupApi from ansible_collections.dellemc.powerstore.tests.unit.plugins.module_utils.mock_api_exception \ import MockApiException -from ansible_collections.dellemc.powerstore.plugins.module_utils.storage.dell \ - import utils - -utils.get_logger = MagicMock() -utils.get_powerstore_connection = MagicMock() -utils.PowerStoreException = MagicMock() -from ansible.module_utils import basic -basic.AnsibleModule = MagicMock() from ansible_collections.dellemc.powerstore.plugins.modules.volumegroup import PowerStoreVolumeGroup