summaryrefslogtreecommitdiffstats
path: root/ansible_collections/purestorage/fusion
diff options
context:
space:
mode:
Diffstat (limited to 'ansible_collections/purestorage/fusion')
-rw-r--r--ansible_collections/purestorage/fusion/.github/workflows/ansible-lint.yaml4
-rw-r--r--ansible_collections/purestorage/fusion/.github/workflows/black.yaml2
-rw-r--r--ansible_collections/purestorage/fusion/.github/workflows/create-release.yaml4
-rw-r--r--ansible_collections/purestorage/fusion/.github/workflows/main.yml25
-rw-r--r--ansible_collections/purestorage/fusion/.github/workflows/rh_automation_hub_token_keep_alive.yml19
-rw-r--r--ansible_collections/purestorage/fusion/.github/workflows/stale.yml2
-rw-r--r--ansible_collections/purestorage/fusion/CHANGELOG.rst23
-rw-r--r--ansible_collections/purestorage/fusion/FILES.json135
-rw-r--r--ansible_collections/purestorage/fusion/MANIFEST.json4
-rw-r--r--ansible_collections/purestorage/fusion/README.md12
-rw-r--r--ansible_collections/purestorage/fusion/changelogs/.plugin-cache.yaml2
-rw-r--r--ansible_collections/purestorage/fusion/changelogs/changelog.yaml36
-rw-r--r--ansible_collections/purestorage/fusion/meta/runtime.yml2
-rw-r--r--ansible_collections/purestorage/fusion/plugins/module_utils/errors.py2
-rw-r--r--ansible_collections/purestorage/fusion/plugins/module_utils/parsing.py2
-rw-r--r--ansible_collections/purestorage/fusion/plugins/module_utils/prerequisites.py2
-rw-r--r--ansible_collections/purestorage/fusion/plugins/module_utils/snapshots.py29
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_api_client.py11
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_array.py28
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_az.py8
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_hap.py6
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_ni.py7
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_nig.py8
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_pg.py37
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_pp.py35
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_ra.py13
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_region.py8
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_sc.py8
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_se.py9
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_ss.py9
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_tenant.py8
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_ts.py8
-rw-r--r--ansible_collections/purestorage/fusion/plugins/modules/fusion_volume.py157
-rw-r--r--ansible_collections/purestorage/fusion/test/config.yaml2
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_api_client.py15
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_array.py25
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_az.py3
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_hap.py3
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_info.py1
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_nig.py5
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_pg.py5
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_pp.py21
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_ra.py2
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_region.py4
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_sc.py4
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_se.py5
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_ss.py4
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_tenant.py4
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_ts.py4
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/test_fusion_volume.py150
-rw-r--r--ansible_collections/purestorage/fusion/tests/functional/utils.py15
-rw-r--r--ansible_collections/purestorage/fusion/tests/helpers.py8
-rw-r--r--ansible_collections/purestorage/fusion/tests/unit/mocks/operation_mock.py14
-rw-r--r--ansible_collections/purestorage/fusion/tests/unit/module_utils/test_parsing.py47
-rw-r--r--ansible_collections/purestorage/fusion/tests/unit/modules/test_fusion_az.py10
55 files changed, 811 insertions, 205 deletions
diff --git a/ansible_collections/purestorage/fusion/.github/workflows/ansible-lint.yaml b/ansible_collections/purestorage/fusion/.github/workflows/ansible-lint.yaml
index 0b2102184..384c5ac93 100644
--- a/ansible_collections/purestorage/fusion/.github/workflows/ansible-lint.yaml
+++ b/ansible_collections/purestorage/fusion/.github/workflows/ansible-lint.yaml
@@ -1,5 +1,5 @@
-name: Ansible Lint # feel free to pick your own name
-on: [push, pull_request]
+name: Ansible Lint # feel free to pick your own name
+"on": [push, pull_request]
jobs:
build:
diff --git a/ansible_collections/purestorage/fusion/.github/workflows/black.yaml b/ansible_collections/purestorage/fusion/.github/workflows/black.yaml
index 68061652a..10b16296c 100644
--- a/ansible_collections/purestorage/fusion/.github/workflows/black.yaml
+++ b/ansible_collections/purestorage/fusion/.github/workflows/black.yaml
@@ -1,6 +1,6 @@
name: Black
-on: [push, pull_request]
+"on": [push, pull_request]
jobs:
lint:
diff --git a/ansible_collections/purestorage/fusion/.github/workflows/create-release.yaml b/ansible_collections/purestorage/fusion/.github/workflows/create-release.yaml
index 25725c15d..68da05e4d 100644
--- a/ansible_collections/purestorage/fusion/.github/workflows/create-release.yaml
+++ b/ansible_collections/purestorage/fusion/.github/workflows/create-release.yaml
@@ -1,6 +1,6 @@
name: Release Collection
-on: workflow_dispatch
+"on": workflow_dispatch
jobs:
create_github_release:
runs-on: ubuntu-latest
@@ -23,7 +23,7 @@ jobs:
if [[ "$response" == *"$RELEASE_VERSION"* ]]; then
trap "exit 1" EXIT
echo "Error: Tag $RELEASE_VERSION already exists"
- exit 1
+ exit 1
fi
- name: Extract changelog
diff --git a/ansible_collections/purestorage/fusion/.github/workflows/main.yml b/ansible_collections/purestorage/fusion/.github/workflows/main.yml
index da0a69969..5c9a3914b 100644
--- a/ansible_collections/purestorage/fusion/.github/workflows/main.yml
+++ b/ansible_collections/purestorage/fusion/.github/workflows/main.yml
@@ -1,6 +1,6 @@
name: Pure Storage Ansible CI
-on:
+"on":
pull_request:
push:
schedule:
@@ -13,36 +13,23 @@ jobs:
strategy:
matrix:
ansible:
- - stable-2.11
- - stable-2.12
- - stable-2.13
- stable-2.14
- stable-2.15
+ - stable-2.16
- devel
python-version:
- - 3.8
- 3.9
- "3.10"
- "3.11"
exclude:
- - python-version: "3.11"
- ansible: stable-2.11
- - python-version: "3.11"
- ansible: stable-2.12
- - python-version: "3.11"
- ansible: stable-2.13
- - python-version: "3.10"
- ansible: stable-2.11
- - python-version: 3.8
- ansible: stable-2.14
- - python-version: 3.8
- ansible: stable-2.15
- - python-version: 3.8
+ - python-version: 3.9
+ ansible: stable-2.16
+ - python-version: 3.9
ansible: devel
steps:
- name: Check out code
uses: actions/checkout@v3
-
+
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
diff --git a/ansible_collections/purestorage/fusion/.github/workflows/rh_automation_hub_token_keep_alive.yml b/ansible_collections/purestorage/fusion/.github/workflows/rh_automation_hub_token_keep_alive.yml
new file mode 100644
index 000000000..f4e0a667b
--- /dev/null
+++ b/ansible_collections/purestorage/fusion/.github/workflows/rh_automation_hub_token_keep_alive.yml
@@ -0,0 +1,19 @@
+---
+name: "Red Hat Automation Hub - Keep token alive"
+# The SSO token to upload content to Automation Hub must be accessed once every 30 days or it will be turned off
+
+"on":
+ schedule:
+ - cron: '0 12 1,15 * *' # run 12pm on the 1st and 15th of the month
+
+jobs:
+ keep_rh_sso_token_alive:
+ runs-on: "ubuntu-latest"
+ steps:
+ - name: "Run curl command"
+ run: |
+ curl ${{ secrets.RH_AUTOMATION_HUB_URL }} \
+ -d grant_type=refresh_token \
+ -d client_id="cloud-services" \
+ -d refresh_token="${{ secrets.RH_AUTOMATION_HUB_TOKEN }}" \
+ --fail --silent --show-error --output /dev/null
diff --git a/ansible_collections/purestorage/fusion/.github/workflows/stale.yml b/ansible_collections/purestorage/fusion/.github/workflows/stale.yml
index 7bbc0505b..ee7c9796e 100644
--- a/ansible_collections/purestorage/fusion/.github/workflows/stale.yml
+++ b/ansible_collections/purestorage/fusion/.github/workflows/stale.yml
@@ -1,6 +1,6 @@
name: Mark stale issues and pull requests
-on:
+"on":
schedule:
- cron: "0 0 * * *"
diff --git a/ansible_collections/purestorage/fusion/CHANGELOG.rst b/ansible_collections/purestorage/fusion/CHANGELOG.rst
index b4d9bd6ae..b6a0f071a 100644
--- a/ansible_collections/purestorage/fusion/CHANGELOG.rst
+++ b/ansible_collections/purestorage/fusion/CHANGELOG.rst
@@ -5,6 +5,29 @@ Purestorage.Fusion Release Notes
.. contents:: Topics
+v1.6.1
+======
+
+Minor Changes
+-------------
+
+- fusion_volume - Allow creating a new volume from already existing volume or volume snapshot
+
+v1.6.0
+======
+
+Minor Changes
+-------------
+
+- all modules - return resource's id parameter on update and create.
+- fusion_array - added `apartment_id` argument, which can be used when creating an array.
+- fusion_pg - introduced `destroy_snapshots_on_delete` which, if set to true, ensures that before deleting placement group, snapshots within the placement group will be deleted.
+- fusion_pp - 'local_rpo' duration parsing documented, 'local_retention' minimum value fixed
+- fusion_pp - Allow leading zeros in duration strings
+- fusion_pp - Change the minimum value of the protection policy local retention from 1 to 10
+- fusion_pp - introduced `destroy_snapshots_on_delete` which, if set to true, ensures that before deleting protection policy, snapshots within the protection policy will be deleted.
+- fusion_volume - Allow creating a new volume from already existing volume or volume snapshot
+
v1.5.0
======
diff --git a/ansible_collections/purestorage/fusion/FILES.json b/ansible_collections/purestorage/fusion/FILES.json
index b3f73b7e0..ad0452035 100644
--- a/ansible_collections/purestorage/fusion/FILES.json
+++ b/ansible_collections/purestorage/fusion/FILES.json
@@ -15,17 +15,24 @@
"format": 1
},
{
+ "name": "changelogs/fragments",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b568495166ca2ef38576e62cc6f1eb2d1f4caa988b020112e14650d37510dd83",
+ "chksum_sha256": "17ac55399ed69cbac46280c27dde9825e556a3b5214ff7defef12cc1dbbae598",
"format": 1
},
{
"name": "changelogs/.plugin-cache.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "492bf617d0924a14708a862efd096e1a032e1a1243f25e2287e44a6e072e2f1a",
+ "chksum_sha256": "64d8cc09b182d4991facb3abb8835c821b4e0cb72d6dd687ddbe16402b6209cc",
"format": 1
},
{
@@ -347,7 +354,7 @@
"name": "tests/unit/modules/test_fusion_az.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "75be72264bf7d95ddc73d72c4763b6e877a05feaab2f6d9b91a55448bb77af51",
+ "chksum_sha256": "7d6b7a4a5a233ee47c6788d370bf1c6a6da5adf9b758b43c6d5557ba87b4dc58",
"format": 1
},
{
@@ -368,7 +375,7 @@
"name": "tests/unit/mocks/operation_mock.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aaa5ad3b4a9bcd10a95947af5f06ec4153512927b56d94f4d442da6007d43c7b",
+ "chksum_sha256": "373ea55faf5262f157724aaf6d1ca31b963415ad1b180b2fa7833983acd1d8f2",
"format": 1
},
{
@@ -417,7 +424,7 @@
"name": "tests/unit/module_utils/test_parsing.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "58c8e7b81680984e3e606cc56210aa8afb93c020939f1d3d585b5cf7de61c513",
+ "chksum_sha256": "a7efaf296b085c6ffbf5174218e575491dcd850f74a159068d0004222d6fade6",
"format": 1
},
{
@@ -438,14 +445,14 @@
"name": "tests/functional/test_fusion_region.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8d108a21480c4cb9c9d2810e809ea876173b3d43621f417c0957c77d21f33f76",
+ "chksum_sha256": "5ba0b74a3580885a0e3dc5693adb85c1d863fe664588275c175131d59122b7f9",
"format": 1
},
{
"name": "tests/functional/test_fusion_ss.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "676bba88edd7f73957c605356d31f4bd61cd144d354280c373beb3689196d5cd",
+ "chksum_sha256": "6b44ef093fcfed0897a14395095185ac6bc1dd6a5f9b153c0e31857734a9a10e",
"format": 1
},
{
@@ -459,56 +466,56 @@
"name": "tests/functional/test_fusion_volume.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b6a8f18e610fcd4f2aea719e5b51ff58ef6f6b06412afd98309255ccab7f8a4",
+ "chksum_sha256": "d307a55f86ea7683542e58d1416fe8d005d3dfcf65b84c8bd6b0f5c914e2aadf",
"format": 1
},
{
"name": "tests/functional/test_fusion_ts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dc844fc260f337525396d47da3e012fbb2f1f5188a96c3d1071515bdac879583",
+ "chksum_sha256": "5dadaf161e2daf306ef5d0eb72dd8e53db398a630f82b6d511fab4e836991489",
"format": 1
},
{
"name": "tests/functional/test_fusion_pg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4da9f7a334491933d40fe8d32fbae767393f84d744537a7d03a57d84a1693b38",
+ "chksum_sha256": "8df05411ef3cd13bd9f7436df88b7bb4c0611a3db23988435b5cc39e9546a967",
"format": 1
},
{
"name": "tests/functional/test_fusion_nig.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f20b2ab1eed1bd182d68a00198537f960e9c7e844cfb8df3c99922e98e2365c1",
+ "chksum_sha256": "a06addf4b81f91e57c7b2413da2a39279b3a794fecab23c3bb2a4609c22873f1",
"format": 1
},
{
"name": "tests/functional/test_fusion_se.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "79d30463a37430a6a697778bb58fe2ced187672ec74ddae6b98f191069931b04",
+ "chksum_sha256": "ad77974f2c4e7ea6ee3681c57ccaf235b2401e83d299495c862a717f6f2b7199",
"format": 1
},
{
"name": "tests/functional/test_fusion_az.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6b7e24d40c1268b1ce0de3557210fbd89e97441dcd384522263f5982a5922b5",
+ "chksum_sha256": "39d40d8fee3e346a8dc7db8becf15c5149fbf13d1af6e29b2325a6dc9f8e9624",
"format": 1
},
{
"name": "tests/functional/test_fusion_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "05d60add74e73360eefd8679e808c2c5c5c774726a15c29d923dd077099e9537",
+ "chksum_sha256": "417845afcefefa6a2e739be86ed8ef7474b43409d44df3079bc4c537ff0821df",
"format": 1
},
{
"name": "tests/functional/test_fusion_hap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a8ffe64ef5a561e2eb102f58b20f62c99c8a79022be63976f6e8c19608178ab",
+ "chksum_sha256": "b7f1abe557c37b29f2a9270636f8b81745d72281141caac0fb0931a79dd391b4",
"format": 1
},
{
@@ -529,56 +536,56 @@
"name": "tests/functional/test_fusion_sc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cf1794f2f91b496adc54131be84e1ea81263ccf603cf648fecd0a52c7a1da467",
+ "chksum_sha256": "b3d781841cc7f3d2956f48dffd0e6ef35a0121841a1a0ac6915068c60ed5bda2",
"format": 1
},
{
"name": "tests/functional/test_fusion_ra.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "718b4be5026d83e2fe3fefe6838637efce66d9880c635a80603844266b3e926c",
+ "chksum_sha256": "36206507be9b65d09a4e01ff75740f6507f5a987180dde6f2d720ea76abc9b9b",
"format": 1
},
{
"name": "tests/functional/test_fusion_tenant.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b5c6413737db89d121c98f7798b36bb736b367fb6c2ee1651645c742822f9b66",
+ "chksum_sha256": "59d4786a7dfb78f72ebca838b7dbfda7444a861d7113b50ddebffd82bea56ade",
"format": 1
},
{
"name": "tests/functional/utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6e339b28c2b3ed78108244bde3950424b3acc81a6a3b9c8cd7b32a53fbd5ba9",
+ "chksum_sha256": "e3d1d3cbd790a64d783f52914e52158e339a7c7eb86c6cb63546d72820e6d6c5",
"format": 1
},
{
"name": "tests/functional/test_fusion_api_client.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "44f1df7dfe3c53b30ae7c2c2fd2873b651f2306bba67a26310a8c2d86c53f04e",
+ "chksum_sha256": "5010777699d6259c58c38e7e51c84baa554b484736516ac180f3b1d3b5f844f8",
"format": 1
},
{
"name": "tests/functional/test_fusion_array.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "910cd4c0859534f5de3b8cb743c9f549b93f25c0f18399158adff63b933a8110",
+ "chksum_sha256": "ca4057d295d239c6c6e6afb7e701f9d337fb44a2dbaf29bb5805cbed80bbe93e",
"format": 1
},
{
"name": "tests/functional/test_fusion_pp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3578756616fff28885b379a93221c3dfe8d083a9d685bd8b16878b7f9bf045c9",
+ "chksum_sha256": "c45337495b95f164eed6e3e6d14c038246d042f16315aea494276380f8afa370",
"format": 1
},
{
"name": "tests/helpers.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "74d50a53434e0ca164aa41ea5f272755e9b6ad0dc105d3eec53f62d3e188034c",
+ "chksum_sha256": "24f55093b6e7486c6c6c6a9cf57875ec69496ac23253f1c5a7f79c870c00d38a",
"format": 1
},
{
@@ -841,6 +848,20 @@
"format": 1
},
{
+ "name": "test",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "test/config.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9a009a349eaaf78c93ff56072d2ef171937bdb884e4976592ab5aaa9c68e1044",
+ "format": 1
+ },
+ {
"name": "plugins",
"ftype": "dir",
"chksum_type": null,
@@ -858,42 +879,42 @@
"name": "plugins/modules/fusion_ts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91e740ffbf27ab279cc6fbd07b5a59e92de941a4e88f437040eae89c1b8f1f3b",
+ "chksum_sha256": "6d4c3f141409f2b1a5128912dbfe14341e17f6a9e5c20d14f3a5e82b75da4462",
"format": 1
},
{
"name": "plugins/modules/fusion_nig.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59cd2a72c5544ebf83ff6fe239f623ec03b4de84efb7cb08fdf4b4159544bc2c",
+ "chksum_sha256": "c220a2793545a832096d78d5d926a7a3037a828a0f2e042601e7e00afa29471b",
"format": 1
},
{
"name": "plugins/modules/fusion_api_client.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5b92104038365e11b958a75a521a843c7b599e950e1d7815ff40a01a519dfff5",
+ "chksum_sha256": "a0e35d215e9cce9b2f5e64e8661a12414ddea48df96a24e0f7b7ae9071aad43e",
"format": 1
},
{
"name": "plugins/modules/fusion_ni.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5edf635cb12288af965649f3941bac2f1eea781c2e23793ac40988faedd34735",
+ "chksum_sha256": "148fdf12357a1b56c30343bb2a46b3d4cc2ff4f179f667c764d64101abc5057b",
"format": 1
},
{
"name": "plugins/modules/fusion_ss.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c278ef52dbd80a2c143b56ace8f31ebcca5ae76426bc7e38bea3e7e66a1a5742",
+ "chksum_sha256": "9ffdfd9f3ae2fa8df1a37b52370cc49e265801d25efcc17eb65649d92f72d4d9",
"format": 1
},
{
"name": "plugins/modules/fusion_pp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29b9019589464b7650892f84ebe112d03f38e03e8c804d6ce35401f85e31603f",
+ "chksum_sha256": "63543885c2adc09b3f829f0600774cf2ca098010ee2c9b58ce359ed383d7a780",
"format": 1
},
{
@@ -907,42 +928,42 @@
"name": "plugins/modules/fusion_array.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0edaabce3e589722d0dd299f7f81d66811351e678046068fae179ad3f331fa4e",
+ "chksum_sha256": "6baebe9c43933cc7bc0c43455a4019eb88805b0f11671a2331cc86bb8775d438",
"format": 1
},
{
"name": "plugins/modules/fusion_az.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f0e9ea0a969913323e917d5b7d631c38e33b3e55a3b641cf553c8ea01228f0a5",
+ "chksum_sha256": "ecaf8c75e0941895ba3b8f349c25049d7e2d6eb2468a609926d57c2d865ba264",
"format": 1
},
{
"name": "plugins/modules/fusion_pg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3c03eb5a59d749a954fe09d4c2a57ec36d30f9bdd51565c8e1e3d3e293d2bbc5",
+ "chksum_sha256": "819e0298797184fd0a5d54fdb6dcebc9e8fad118a353c217311eddd7608ac2d4",
"format": 1
},
{
"name": "plugins/modules/fusion_volume.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e2b6a4837e1abc3efc2fa88707cfa80f618b800bccdad6bd5a5ac3f60ba77d14",
+ "chksum_sha256": "ccf9e89f5c10eac9d992ac0740c082ebaaedf7d8d9ded38322223cc57a2f98d5",
"format": 1
},
{
"name": "plugins/modules/fusion_tenant.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03823b7283e0de940ee3e95bf5645595e4330759ad7dd18f0411c319774ec173",
+ "chksum_sha256": "18887fdb6f7a44b647db0e25f726d605e00ded8396bc9841b29ddec1b56e101e",
"format": 1
},
{
"name": "plugins/modules/fusion_se.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "355892de73b5d265e1e57e8ff31b3dd0775c04a191ded999131ebbfdbbcd7231",
+ "chksum_sha256": "9c77f1b938823461f586c66949527a5377dff942a7ec1024d729f190b2e127fa",
"format": 1
},
{
@@ -956,21 +977,21 @@
"name": "plugins/modules/fusion_ra.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4a1bd14fe1038fbf09d4196143f4ac262ef7627ee550ea2efbaeceaa3e0a6176",
+ "chksum_sha256": "20c1a2bbde557ebc6b03453552c2a2f718f11271ac96d75e7beb43c04095157c",
"format": 1
},
{
"name": "plugins/modules/fusion_sc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7302c71a969dbbc3fb636455ee16ef807a3e2c212d307c305b86504b2b42603c",
+ "chksum_sha256": "12711136fb3fa243fd65f15df009f9f0b68d5ee9fef9b11f5f7d7de38526afdb",
"format": 1
},
{
"name": "plugins/modules/fusion_region.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6cb89588cca8681cfc12651ace18375eba88d2aaaacf2ece2d7652d9821fde9",
+ "chksum_sha256": "1bb063fced01a15617c99e4be32a95265e1678c75fc892ea3e1b9e93f3f683fb",
"format": 1
},
{
@@ -984,7 +1005,7 @@
"name": "plugins/modules/fusion_hap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ffc4d041a552ac1d45ab51868428f9281829d2f345581eef8f379b1692e50a1a",
+ "chksum_sha256": "0b3e80b8cc3d42fc06b657d01258f24a805b6027ccfdc4286ddd66ddce554ea1",
"format": 1
},
{
@@ -1019,7 +1040,7 @@
"name": "plugins/module_utils/prerequisites.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "589f5ad7eed9dfe57263a9d3ec7dd6b179da0406aa2a6706ec056f3ab60af5cd",
+ "chksum_sha256": "d4c21413eceda5c98229edd0999d45c3b87554fae9eeb096322d03dab91ac870",
"format": 1
},
{
@@ -1033,14 +1054,14 @@
"name": "plugins/module_utils/errors.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fa7c577ce38810b137980e87e6e5b87e95fb43e101d02652df7cbb434f630699",
+ "chksum_sha256": "8b39a68c54dd07e3061824d2ad60ba4f9cebbf7b3c020283ceb3859e4e0e28a9",
"format": 1
},
{
"name": "plugins/module_utils/parsing.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "efe7b474e24d7fa53dc134f7fd1e4062542a22d5ea9f8b16715ab8a353d1d953",
+ "chksum_sha256": "61e0fac0fa4ff6bbd1eb7f9dd1ba1b6822965f5f7c7691537222d3af37e725c2",
"format": 1
},
{
@@ -1051,6 +1072,13 @@
"format": 1
},
{
+ "name": "plugins/module_utils/snapshots.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f7571aba639702400e659241f9d8f61dd72f6ef3119b0af5296d7522dbd5125f",
+ "format": 1
+ },
+ {
"name": "plugins/module_utils/startup.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -1124,35 +1152,42 @@
"name": ".github/workflows/ansible-lint.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4c85688d98b71e3a6594530a362cd5d2cf83842ceaccd0e0fc76e233777c1cef",
+ "chksum_sha256": "62dbc43cafdab8da066ba0d86a08924e433f8b2919cdef935c116c5962d3a572",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/rh_automation_hub_token_keep_alive.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3c7f513c85853a9f152635f5fc9f4f8a1e621cc8b2a40c405d9efc69830800f6",
"format": 1
},
{
"name": ".github/workflows/stale.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0bdef4889afabcd627fc30711a0809c7468b8c9e64cbcebe1334f794a41e7bd9",
+ "chksum_sha256": "544ccc9f17e16d9087802e3dcec69741e6ff79e31cf7302947ce2c08126ce1d4",
"format": 1
},
{
"name": ".github/workflows/black.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c62a1a4fcc1e00f3e8f295863e304db520124bfd3e9b0c2cccd6d78343b679c5",
+ "chksum_sha256": "b82c6a8af5e7c7d2113fecafa178bf6df94de434d4dc6e2ed6c3bc695da74f41",
"format": 1
},
{
"name": ".github/workflows/create-release.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "43ea888cb2b22ddc86ea989f75967accaff0065cc43c39a0043ba6cf2f424378",
+ "chksum_sha256": "12ebf07984e4908dd2a6bed45d8bf38641bf3f264fe30ead9ce2849e6fcc8eb5",
"format": 1
},
{
"name": ".github/workflows/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0c8c2578e81d44e4a9611c57a59c6fbc7dd947ff149a169ea65f497484d6d4a4",
+ "chksum_sha256": "60e50d69898144d914ad2af759c744bd3ec8ccc78141cbeb13b850f283e20653",
"format": 1
},
{
@@ -1166,7 +1201,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a753d4c6dc5cdd493fd60f147cf68f644ec6f301b895fc249093914db1cf3ab1",
+ "chksum_sha256": "2958e9b57938d749df6845d5d1a7e65c499990637af1056923ed6efa22c5684e",
"format": 1
},
{
@@ -1180,7 +1215,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9f829699b200db8a8282ce6f44d6ae28a2e3377e0e611b0d327db64b0cbba321",
+ "chksum_sha256": "359c08cf506ebfd67477b25cc2f4763a1495f398cfb3cc9dd2a29595dce990db",
"format": 1
},
{
@@ -1201,7 +1236,7 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "28eab01a890a0719cf1908791d9575a4d47014547796bb077f44702dbbc5632a",
+ "chksum_sha256": "9c8780730bed93a88dcaafd561c2a40c06cc7add04279bce943a6e2a7a2f8778",
"format": 1
}
],
diff --git a/ansible_collections/purestorage/fusion/MANIFEST.json b/ansible_collections/purestorage/fusion/MANIFEST.json
index 4fe3bc8b5..877ab80f8 100644
--- a/ansible_collections/purestorage/fusion/MANIFEST.json
+++ b/ansible_collections/purestorage/fusion/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "purestorage",
"name": "fusion",
- "version": "1.5.0",
+ "version": "1.6.1",
"authors": [
"Pure Storage Ansible Team <pure-ansible-team@purestorage.com>"
],
@@ -27,7 +27,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3e406206ea2f67e0a9846219a9d5d2813aef76437e1b05d12d341aded53cfd13",
+ "chksum_sha256": "fcdf40d7eabc65ac35369e36b6ed40579ce799ee0ea94caed4b7ab06c0efd0b5",
"format": 1
},
"format": 1
diff --git a/ansible_collections/purestorage/fusion/README.md b/ansible_collections/purestorage/fusion/README.md
index b2a36de10..0bb22423d 100644
--- a/ansible_collections/purestorage/fusion/README.md
+++ b/ansible_collections/purestorage/fusion/README.md
@@ -4,14 +4,20 @@
<img src="https://github.com/Pure-Storage-Ansible/Fusion-Collection/workflows/Pure%20Storage%20Ansible%20CI/badge.svg">
<a href="https://github.com/psf/black"><img src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
+# DEPRECATION NOTICE
+
+The Pure Storage Fusion Ansible Collection is no longer being developed and is being deprecated.
+
+No further development work will be performed on this repo and the repo will be archived.
+
# Pure Storage Fusion Collection
-The Pure Storage Fusion collection consists of the latest versions of the Fusion modules.
+The Pure Storage Fusion collection consists of the latest versions of the Fusion v1 modules.
## Requirements
-- ansible-core >= 2.11
-- Python >= 3.8
+- ansible-core >= 2.14.0
+- Python >= 3.9
- Authorized API Application ID for Pure Storage Pure1 and associated Private Key
- Refer to Pure Storage documentation on how to create these.
- purefusion >= 1.0.4
diff --git a/ansible_collections/purestorage/fusion/changelogs/.plugin-cache.yaml b/ansible_collections/purestorage/fusion/changelogs/.plugin-cache.yaml
index 23a38bf01..190d97ce5 100644
--- a/ansible_collections/purestorage/fusion/changelogs/.plugin-cache.yaml
+++ b/ansible_collections/purestorage/fusion/changelogs/.plugin-cache.yaml
@@ -111,4 +111,4 @@ plugins:
strategy: {}
test: {}
vars: {}
-version: 1.5.0
+version: 1.6.1
diff --git a/ansible_collections/purestorage/fusion/changelogs/changelog.yaml b/ansible_collections/purestorage/fusion/changelogs/changelog.yaml
index 82ef323c8..c5d3f432d 100644
--- a/ansible_collections/purestorage/fusion/changelogs/changelog.yaml
+++ b/ansible_collections/purestorage/fusion/changelogs/changelog.yaml
@@ -343,3 +343,39 @@ releases:
- 3289_functests_pp_pg_ra.yml
- 99_update_protection_policy_retention_description.yaml
release_date: '2023-05-31'
+ 1.6.0:
+ changes:
+ minor_changes:
+ - all modules - return resource's id parameter on update and create.
+ - fusion_array - added `apartment_id` argument, which can be used when creating
+ an array.
+ - fusion_pg - introduced `destroy_snapshots_on_delete` which, if set to true,
+ ensures that before deleting placement group, snapshots within the placement
+ group will be deleted.
+ - fusion_pp - 'local_rpo' duration parsing documented, 'local_retention' minimum
+ value fixed
+ - fusion_pp - Allow leading zeros in duration strings
+ - fusion_pp - Change the minimum value of the protection policy local retention
+ from 1 to 10
+ - fusion_pp - introduced `destroy_snapshots_on_delete` which, if set to true,
+ ensures that before deleting protection policy, snapshots within the protection
+ policy will be deleted.
+ - fusion_volume - Allow creating a new volume from already existing volume or
+ volume snapshot
+ fragments:
+ - 148_add_apartment_id_to_fusion_array.yml
+ - 151_create_volume_using_existing_volume_or_snapshot.yaml
+ - 152_fix_rpo_local_retention_doc.yaml
+ - 154_add_destroy_snapshots_on_delete_to_pp_and_pg.yml
+ - 156_allow_leading_zeros.yaml
+ - 159_fix_protection_policy_local_retention_validation.yaml
+ - 160_add_id_on_exit.yml
+ release_date: '2023-07-31'
+ 1.6.1:
+ changes:
+ minor_changes:
+ - fusion_volume - Allow creating a new volume from already existing volume or
+ volume snapshot
+ fragments:
+ - 151_create_volume_using_existing_volume_or_snapshot.yaml
+ release_date: '2024-02-08'
diff --git a/ansible_collections/purestorage/fusion/meta/runtime.yml b/ansible_collections/purestorage/fusion/meta/runtime.yml
index 1812440b2..6af15681b 100644
--- a/ansible_collections/purestorage/fusion/meta/runtime.yml
+++ b/ansible_collections/purestorage/fusion/meta/runtime.yml
@@ -1,5 +1,5 @@
---
-requires_ansible: ">=2.11.0"
+requires_ansible: ">=2.14.0"
plugin_routing:
modules:
fusion_tn:
diff --git a/ansible_collections/purestorage/fusion/plugins/module_utils/errors.py b/ansible_collections/purestorage/fusion/plugins/module_utils/errors.py
index 0edf364cf..f3d574edc 100644
--- a/ansible_collections/purestorage/fusion/plugins/module_utils/errors.py
+++ b/ansible_collections/purestorage/fusion/plugins/module_utils/errors.py
@@ -162,7 +162,7 @@ def format_failed_fusion_operation_exception(exception):
if not code:
code = error.http_code
operation_name = op.request_type
- except Exception as e:
+ except Exception:
pass
output = ""
diff --git a/ansible_collections/purestorage/fusion/plugins/module_utils/parsing.py b/ansible_collections/purestorage/fusion/plugins/module_utils/parsing.py
index a2cd75245..1bcb8b812 100644
--- a/ansible_collections/purestorage/fusion/plugins/module_utils/parsing.py
+++ b/ansible_collections/purestorage/fusion/plugins/module_utils/parsing.py
@@ -11,7 +11,7 @@ __metaclass__ = type
METRIC_SUFFIXES = ["K", "M", "G", "T", "P"]
duration_pattern = re.compile(
- r"^((?P<Y>[1-9]\d*)Y)?((?P<W>[1-9]\d*)W)?((?P<D>[1-9]\d*)D)?(((?P<H>[1-9]\d*)H)?((?P<M>[1-9]\d*)M)?)?$"
+ r"^((?P<Y>\d+)Y)?((?P<W>\d+)W)?((?P<D>\d+)D)?(((?P<H>\d+)H)?((?P<M>\d+)M)?)?$"
)
duration_transformation = {
"Y": 365 * 24 * 60,
diff --git a/ansible_collections/purestorage/fusion/plugins/module_utils/prerequisites.py b/ansible_collections/purestorage/fusion/plugins/module_utils/prerequisites.py
index a4edaf341..db00a9c6f 100644
--- a/ansible_collections/purestorage/fusion/plugins/module_utils/prerequisites.py
+++ b/ansible_collections/purestorage/fusion/plugins/module_utils/prerequisites.py
@@ -136,7 +136,7 @@ def _check_import(ansible_module, module, package=None, version_requirements=Non
:param version_requirements: a string, version requirements for 'package'
"""
try:
- mod = importlib.import_module(module)
+ importlib.import_module(module)
except ImportError:
ansible_module.fail_json(
msg="Error: Python package '{0}' required and missing".format(module)
diff --git a/ansible_collections/purestorage/fusion/plugins/module_utils/snapshots.py b/ansible_collections/purestorage/fusion/plugins/module_utils/snapshots.py
new file mode 100644
index 000000000..ed34c1c0e
--- /dev/null
+++ b/ansible_collections/purestorage/fusion/plugins/module_utils/snapshots.py
@@ -0,0 +1,29 @@
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+try:
+ import fusion as purefusion
+except ImportError:
+ pass
+
+from ansible_collections.purestorage.fusion.plugins.module_utils.operations import (
+ await_operation,
+)
+
+
+def delete_snapshot(fusion, snap, snapshots_api):
+ patch = purefusion.SnapshotPatch(destroyed=purefusion.NullableBoolean(True))
+ op = snapshots_api.update_snapshot(
+ body=patch,
+ tenant_name=snap.tenant.name,
+ tenant_space_name=snap.tenant_space.name,
+ snapshot_name=snap.name,
+ )
+ await_operation(fusion, op)
+ op = snapshots_api.delete_snapshot(
+ tenant_name=snap.tenant.name,
+ tenant_space_name=snap.tenant_space.name,
+ snapshot_name=snap.name,
+ )
+ await_operation(fusion, op)
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_api_client.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_api_client.py
index 39860449d..42254338f 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_api_client.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_api_client.py
@@ -99,14 +99,15 @@ def create_client(module, fusion):
id_api_instance = purefusion.IdentityManagerApi(fusion)
changed = True
+ id = None
if not module.check_mode:
client = purefusion.APIClientPost(
public_key=module.params["public_key"],
display_name=module.params["name"],
)
- id_api_instance.create_api_client(client)
-
- module.exit_json(changed=changed)
+ res = id_api_instance.create_api_client(client)
+ id = res.id
+ module.exit_json(changed=changed, id=id)
def main():
@@ -129,8 +130,8 @@ def main():
create_client(module, fusion)
elif client_id is not None and state == "absent":
delete_client(module, fusion, client_id)
- else:
- module.exit_json(changed=False)
+ if client_id is not None:
+ module.exit_json(changed=False, id=client_id)
module.exit_json(changed=False)
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_array.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_array.py
index f7933eabe..ec94d616f 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_array.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_array.py
@@ -60,6 +60,10 @@ options:
description:
- Appliance ID of the array.
type: str
+ apartment_id:
+ description:
+ - The Apartment ID of the Array.
+ type: str
maintenance_mode:
description:
- "Switch the array into maintenance mode or back.
@@ -123,6 +127,7 @@ def create_array(module, fusion):
"""Create Array"""
array_api_instance = purefusion.ArraysApi(fusion)
+ id = None
if not module.check_mode:
if not module.params["display_name"]:
@@ -135,14 +140,17 @@ def create_array(module, fusion):
host_name=module.params["host_name"],
name=module.params["name"],
appliance_id=module.params["appliance_id"],
+ apartment_id=module.params["apartment_id"],
)
res = array_api_instance.create_array(
array,
availability_zone_name=module.params["availability_zone"],
region_name=module.params["region"],
)
- await_operation(fusion, res)
- return True
+ res_op = await_operation(fusion, res)
+ id = res_op.result.resource.id
+
+ return True, id
def update_array(module, fusion):
@@ -222,6 +230,7 @@ def main():
availability_zone=dict(type="str", required=True, aliases=["az"]),
display_name=dict(type="str"),
region=dict(type="str", required=True),
+ apartment_id=dict(type="str"),
appliance_id=dict(type="str"),
host_name=dict(type="str"),
hardware_type=dict(
@@ -246,17 +255,24 @@ def main():
array = get_array(module, fusion)
changed = False
+ id = None
+ if array is not None:
+ id = array.id
+
if not array and state == "present":
module.fail_on_missing_params(["hardware_type", "host_name", "appliance_id"])
- changed = create_array(module, fusion) | update_array(
+ changed, id = create_array(module, fusion)
+ update_array(
module, fusion
) # update is run to set properties which cannot be set on creation and instead use defaults
elif array and state == "present":
- changed = changed | update_array(module, fusion)
+ changed = update_array(module, fusion)
elif array and state == "absent":
changed = changed | delete_array(module, fusion)
- else:
- module.exit_json(changed=False)
+ module.exit_json(changed=changed)
+
+ if id is not None:
+ module.exit_json(changed=changed, id=id)
module.exit_json(changed=changed)
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_az.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_az.py
index 02647d397..b4a493861 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_az.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_az.py
@@ -112,6 +112,7 @@ def create_az(module, fusion):
az_api_instance = purefusion.AvailabilityZonesApi(fusion)
changed = True
+ id = None
if not module.check_mode:
if not module.params["display_name"]:
display_name = module.params["name"]
@@ -125,9 +126,10 @@ def create_az(module, fusion):
op = az_api_instance.create_availability_zone(
azone, region_name=module.params["region"]
)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=id)
def main():
@@ -152,8 +154,6 @@ def main():
create_az(module, fusion)
elif azone and state == "absent":
delete_az(module, fusion)
- else:
- module.exit_json(changed=False)
module.exit_json(changed=False)
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_hap.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_hap.py
index 3f45ea2dd..c4df0af49 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_hap.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_hap.py
@@ -170,8 +170,10 @@ def create_hap(module, fusion):
display_name=display_name,
)
)
- await_operation(fusion, op)
- module.exit_json(changed=changed)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
+
+ module.exit_json(changed=changed, id=id)
def delete_hap(module, fusion):
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_ni.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_ni.py
index 6816ed841..82c896fac 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_ni.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_ni.py
@@ -162,7 +162,7 @@ def update_ni(module, fusion, ni):
),
)
patches.append(patch)
-
+ id = None
if not module.check_mode:
for patch in patches:
op = ni_api_instance.update_network_interface(
@@ -172,11 +172,12 @@ def update_ni(module, fusion, ni):
array_name=module.params["array"],
net_intf_name=module.params["name"],
)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
changed = len(patches) != 0
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=id)
def main():
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_nig.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_nig.py
index d6056fd5a..d40b813b9 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_nig.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_nig.py
@@ -146,6 +146,7 @@ def create_nig(module, fusion):
):
module.fail_json(msg="`gateway` must be an address in subnet `prefix`")
+ id = None
if not module.check_mode:
display_name = module.params["display_name"] or module.params["name"]
if module.params["group_type"] == "eth":
@@ -171,13 +172,14 @@ def create_nig(module, fusion):
availability_zone_name=module.params["availability_zone"],
region_name=module.params["region"],
)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
changed = True
else:
# to prevent future unintended error
module.warn(f"group_type={module.params['group_type']} is not implemented")
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=id)
def delete_nig(module, fusion):
@@ -220,7 +222,7 @@ def update_nig(module, fusion, nig):
changed = len(patches) != 0
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=nig.id)
def main():
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_pg.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_pg.py
index 57843d896..6d6f0eb94 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_pg.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_pg.py
@@ -36,6 +36,11 @@ options:
type: str
default: present
choices: [ absent, present ]
+ destroy_snapshots_on_delete:
+ description:
+ - "Before deleting placement group, snapshots within the placement group will be deleted."
+ - "If `false` then any snapshots will need to be deleted as a separate step before removing the placement group."
+ type: bool
tenant:
description:
- The name of the tenant.
@@ -116,6 +121,9 @@ from ansible_collections.purestorage.fusion.plugins.module_utils.startup import
from ansible_collections.purestorage.fusion.plugins.module_utils.operations import (
await_operation,
)
+from ansible_collections.purestorage.fusion.plugins.module_utils.snapshots import (
+ delete_snapshot,
+)
def get_pg(module, fusion):
@@ -153,9 +161,10 @@ def create_pg(module, fusion):
tenant_name=module.params["tenant"],
tenant_space_name=module.params["tenant_space"],
)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
- return True
+ return True, id
def update_display_name(module, fusion, patches, pg):
@@ -213,6 +222,16 @@ def delete_pg(module, fusion):
"""Delete Placement Group"""
pg_api_instance = purefusion.PlacementGroupsApi(fusion)
if not module.check_mode:
+ if module.params["destroy_snapshots_on_delete"]:
+ snapshots_api = purefusion.SnapshotsApi(fusion)
+ snapshots = snapshots_api.list_snapshots(
+ placement_group=module.params["name"],
+ tenant_name=module.params["tenant"],
+ tenant_space_name=module.params["tenant_space"],
+ )
+ for snap in snapshots.items:
+ delete_snapshot(fusion, snap, snapshots_api)
+
op = pg_api_instance.delete_placement_group(
placement_group_name=module.params["name"],
tenant_name=module.params["tenant"],
@@ -229,6 +248,7 @@ def main():
argument_spec.update(
dict(
name=dict(type="str", required=True),
+ destroy_snapshots_on_delete=dict(type="bool"),
display_name=dict(type="str"),
tenant=dict(type="str", required=True),
tenant_space=dict(type="str", required=True),
@@ -257,19 +277,28 @@ def main():
state = module.params["state"]
pgroup = get_pg(module, fusion)
+ id = None
+ if pgroup is not None:
+ id = pgroup.id
+
if state == "present" and not pgroup:
module.fail_on_missing_params(
["region", "availability_zone", "storage_service"]
)
- changed = create_pg(module, fusion) or changed
+ changed, id = create_pg(module, fusion) or changed
if module.params["array"]:
# changing placement requires additional update
pgroup = get_pg(module, fusion)
- changed = update_pg(module, fusion, pgroup) or changed
+ changedUpdate = update_pg(module, fusion, pgroup)
+ changed = changed | changedUpdate
elif state == "present" and pgroup:
changed = update_pg(module, fusion, pgroup) or changed
elif state == "absent" and pgroup:
changed = delete_pg(module, fusion) or changed
+ module.exit_json(changed=changed)
+
+ if id is not None:
+ module.exit_json(changed=changed, id=id)
module.exit_json(changed=changed)
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_pp.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_pp.py
index abce9195c..216209d84 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_pp.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_pp.py
@@ -31,6 +31,11 @@ options:
default: present
choices: [ present, absent ]
type: str
+ destroy_snapshots_on_delete:
+ description:
+ - "Before deleting protection policy, snapshots within the protection policy will be deleted."
+ - "If `false` then any snapshots will need to be deleted as a separate step before removing the protection policy."
+ type: bool
display_name:
description:
- The human name of the protection policy.
@@ -39,8 +44,10 @@ options:
local_rpo:
description:
- Recovery Point Objective for snapshots.
- - Value should be specified in minutes.
- Minimum value is 10 minutes.
+ - Value can be provided as m(inutes), h(ours),
+ d(ays), w(eeks), or y(ears).
+ - If no unit is provided, minutes are assumed.
type: str
local_retention:
description:
@@ -95,6 +102,9 @@ from ansible_collections.purestorage.fusion.plugins.module_utils.startup import
from ansible_collections.purestorage.fusion.plugins.module_utils.operations import (
await_operation,
)
+from ansible_collections.purestorage.fusion.plugins.module_utils.snapshots import (
+ delete_snapshot,
+)
def get_pp(module, fusion):
@@ -114,11 +124,13 @@ def create_pp(module, fusion):
pp_api_instance = purefusion.ProtectionPoliciesApi(fusion)
local_rpo = parse_minutes(module, module.params["local_rpo"])
local_retention = parse_minutes(module, module.params["local_retention"])
- if local_retention < 1:
- module.fail_json(msg="Local Retention must be a minimum of 1 minutes")
+ if local_retention < 10:
+ module.fail_json(msg="Local Retention must be a minimum of 10 minutes")
if local_rpo < 10:
module.fail_json(msg="Local RPO must be a minimum of 10 minutes")
+
changed = True
+ id = None
if not module.check_mode:
if not module.params["display_name"]:
display_name = module.params["name"]
@@ -136,9 +148,10 @@ def create_pp(module, fusion):
],
)
)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=id)
def delete_pp(module, fusion):
@@ -146,6 +159,15 @@ def delete_pp(module, fusion):
pp_api_instance = purefusion.ProtectionPoliciesApi(fusion)
changed = True
if not module.check_mode:
+ if module.params["destroy_snapshots_on_delete"]:
+ protection_policy = get_pp(module, fusion)
+ snapshots_api = purefusion.SnapshotsApi(fusion)
+ snapshots = snapshots_api.query_snapshots(
+ protection_policy_id=protection_policy.id
+ )
+ for snap in snapshots.items:
+ delete_snapshot(fusion, snap, snapshots_api)
+
op = pp_api_instance.delete_protection_policy(
protection_policy_name=module.params["name"],
)
@@ -160,6 +182,7 @@ def main():
argument_spec.update(
dict(
name=dict(type="str", required=True),
+ destroy_snapshots_on_delete=dict(type="bool"),
display_name=dict(type="str"),
local_rpo=dict(type="str"),
local_retention=dict(type="str"),
@@ -177,8 +200,6 @@ def main():
create_pp(module, fusion)
elif policy and state == "absent":
delete_pp(module, fusion)
- else:
- module.exit_json(changed=False)
module.exit_json(changed=False)
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_ra.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_ra.py
index 7cfc7d866..c2ae2d5cf 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_ra.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_ra.py
@@ -43,7 +43,7 @@ options:
type: str
api_client_key:
description:
- - The key of API client to assign the role to.
+ - The issuer ID of the API client to assign the role to.
type: str
scope:
description:
@@ -127,7 +127,7 @@ def get_principal(module, fusion):
def user_to_principal(fusion, user_id):
- """Given a human readable Fusion user, such as a Pure 1 App ID
+ """Given a human-readable Fusion user, such as a Pure 1 App ID
return the associated principal
"""
id_api_instance = purefusion.IdentityManagerApi(fusion)
@@ -139,7 +139,7 @@ def user_to_principal(fusion, user_id):
def apiclient_to_principal(fusion, api_client_key):
- """Given an API client key, such as "pure1:apikey:123xXxyYyzYzASDF" (also known as issuer_id),
+ """Given an API client issuer ID, such as "pure1:apikey:123xXxyYyzYzASDF",
return the associated principal
"""
id_api_instance = purefusion.IdentityManagerApi(fusion)
@@ -189,6 +189,7 @@ def create_ra(module, fusion):
ra_api_instance = purefusion.RoleAssignmentsApi(fusion)
changed = True
+ id = None
if not module.check_mode:
principal = get_principal(module, fusion)
scope = get_scope(module.params)
@@ -196,8 +197,10 @@ def create_ra(module, fusion):
op = ra_api_instance.create_role_assignment(
assignment, role_name=module.params["role"]
)
- await_operation(fusion, op)
- module.exit_json(changed=changed)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
+
+ module.exit_json(changed=changed, id=id)
def delete_ra(module, fusion):
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_region.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_region.py
index fbcbff4b0..de40e7dc2 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_region.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_region.py
@@ -96,6 +96,7 @@ def create_region(module, fusion):
reg_api_instance = purefusion.RegionsApi(fusion)
changed = True
+ id = None
if not module.check_mode:
if not module.params["display_name"]:
display_name = module.params["name"]
@@ -106,9 +107,10 @@ def create_region(module, fusion):
display_name=display_name,
)
op = reg_api_instance.create_region(region)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=id)
def delete_region(module, fusion):
@@ -144,7 +146,7 @@ def update_region(module, fusion, region):
)
await_operation(fusion, op)
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=region.id)
def main():
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_sc.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_sc.py
index 2327b8d48..59fc0025e 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_sc.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_sc.py
@@ -160,6 +160,7 @@ def create_sc(module, fusion):
module.fail_json(msg="Size limit is not within the required range")
changed = True
+ id = None
if not module.check_mode:
if not module.params["display_name"]:
display_name = module.params["name"]
@@ -175,9 +176,10 @@ def create_sc(module, fusion):
op = sc_api_instance.create_storage_class(
s_class, storage_service_name=module.params["storage_service"]
)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=id)
def update_sc(module, fusion, s_class):
@@ -201,7 +203,7 @@ def update_sc(module, fusion, s_class):
)
await_operation(fusion, op)
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=s_class.id)
def delete_sc(module, fusion):
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_se.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_se.py
index 9eed4bea0..3a191a166 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_se.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_se.py
@@ -269,7 +269,7 @@ def get_se(module, fusion):
def create_se(module, fusion):
"""Create Storage Endpoint"""
se_api_instance = purefusion.StorageEndpointsApi(fusion)
-
+ id = None
if not module.check_mode:
endpoint_type = None
@@ -307,9 +307,10 @@ def create_se(module, fusion):
region_name=module.params["region"],
availability_zone_name=module.params["availability_zone"],
)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
- module.exit_json(changed=True)
+ module.exit_json(changed=True, id=id)
def delete_se(module, fusion):
@@ -351,7 +352,7 @@ def update_se(module, fusion, se):
changed = len(patches) != 0
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=se.id)
def main():
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_ss.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_ss.py
index 3fdbb07dd..4e6388249 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_ss.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_ss.py
@@ -106,6 +106,7 @@ def create_ss(module, fusion):
ss_api_instance = purefusion.StorageServicesApi(fusion)
changed = True
+ id = None
if not module.check_mode:
if not module.params["display_name"]:
display_name = module.params["name"]
@@ -117,9 +118,10 @@ def create_ss(module, fusion):
hardware_types=module.params["hardware_types"],
)
op = ss_api_instance.create_storage_service(s_service)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=id)
def delete_ss(module, fusion):
@@ -151,6 +153,7 @@ def update_ss(module, fusion, ss):
)
patches.append(patch)
+ id = None
if not module.check_mode:
for patch in patches:
op = ss_api_instance.update_storage_service(
@@ -161,7 +164,7 @@ def update_ss(module, fusion, ss):
changed = len(patches) != 0
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=ss.id)
def main():
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_tenant.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_tenant.py
index 96e890a6b..85224a6c5 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_tenant.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_tenant.py
@@ -87,6 +87,7 @@ def create_tenant(module, fusion):
api_instance = purefusion.TenantsApi(fusion)
changed = True
+ id = None
if not module.check_mode:
if not module.params["display_name"]:
display_name = module.params["name"]
@@ -97,9 +98,10 @@ def create_tenant(module, fusion):
display_name=display_name,
)
op = api_instance.create_tenant(tenant)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=id)
def update_tenant(module, fusion, tenant):
@@ -122,7 +124,7 @@ def update_tenant(module, fusion, tenant):
)
await_operation(fusion, op)
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=tenant.id)
def delete_tenant(module, fusion):
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_ts.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_ts.py
index 33fb0187a..ac60476bc 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_ts.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_ts.py
@@ -95,6 +95,7 @@ def create_ts(module, fusion):
ts_api_instance = purefusion.TenantSpacesApi(fusion)
changed = True
+ id = None
if not module.check_mode:
if not module.params["display_name"]:
display_name = module.params["name"]
@@ -108,9 +109,10 @@ def create_ts(module, fusion):
tspace,
tenant_name=module.params["tenant"],
)
- await_operation(fusion, op)
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=id)
def update_ts(module, fusion, ts):
@@ -138,7 +140,7 @@ def update_ts(module, fusion, ts):
changed = len(patches) != 0
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, id=ts.id)
def delete_ts(module, fusion):
diff --git a/ansible_collections/purestorage/fusion/plugins/modules/fusion_volume.py b/ansible_collections/purestorage/fusion/plugins/modules/fusion_volume.py
index 5b19064f5..38dee8650 100644
--- a/ansible_collections/purestorage/fusion/plugins/modules/fusion_volume.py
+++ b/ansible_collections/purestorage/fusion/plugins/modules/fusion_volume.py
@@ -73,6 +73,21 @@ options:
To clear, assign empty list: host_access_policies: []'
type: list
elements: str
+ source_volume:
+ description:
+ - The source volume name. It must live within the same tenant space.
+ Cannot be used together with `source_snapshot` or `source_volume_snapshot`.
+ type: str
+ source_snapshot:
+ description:
+ - The source snapshot name. It must live within the same tenant space.
+ Cannot be used together with `source_volume`.
+ type: str
+ source_volume_snapshot:
+ description:
+ - The source volume snapshot name. It must live within the same tenant space.
+ Cannot be used together with `source_volume`.
+ type: str
rename:
description:
- New name for volume.
@@ -86,6 +101,7 @@ EXAMPLES = r"""
purestorage.fusion.fusion_volume:
name: foo
storage_class: fred
+ placement_group: pg
size: 1T
tenant: test
tenant_space: space_1
@@ -93,6 +109,31 @@ EXAMPLES = r"""
issuer_id: key_name
private_key_file: "az-admin-private-key.pem"
+- name: Create new volume based on a volume from the same tenant space
+ purestorage.fusion.fusion_volume:
+ name: foo
+ storage_class: fred
+ placement_group: pg
+ tenant: test
+ tenant_space: space_1
+ state: present
+ source_volume: "original_volume_name"
+ issuer_id: key_name
+ private_key_file: "az-admin-private-key.pem"
+
+- name: Create new volume based on a volume snapshot from the same tenant space
+ purestorage.fusion.fusion_volume:
+ name: foo
+ storage_class: fred
+ placement_group: pg
+ tenant: test
+ tenant_space: space_1
+ state: present
+ source_snapshot: "snap"
+ source_volume_snapshot: "vol_snap"
+ issuer_id: key_name
+ private_key_file: "az-admin-private-key.pem"
+
- name: Extend the size of an existing volume named foo
purestorage.fusion.fusion_volume:
name: foo
@@ -116,24 +157,24 @@ EXAMPLES = r"""
RETURN = r"""
"""
-try:
- import fusion as purefusion
-except ImportError:
- pass
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.purestorage.fusion.plugins.module_utils.fusion import (
- fusion_argument_spec,
-)
-from ansible_collections.purestorage.fusion.plugins.module_utils.parsing import (
- parse_number_with_metric_suffix,
+from ansible_collections.purestorage.fusion.plugins.module_utils.operations import (
+ await_operation,
)
from ansible_collections.purestorage.fusion.plugins.module_utils.startup import (
setup_fusion,
)
-from ansible_collections.purestorage.fusion.plugins.module_utils.operations import (
- await_operation,
+from ansible_collections.purestorage.fusion.plugins.module_utils.parsing import (
+ parse_number_with_metric_suffix,
)
+from ansible_collections.purestorage.fusion.plugins.module_utils.fusion import (
+ fusion_argument_spec,
+)
+from ansible.module_utils.basic import AnsibleModule
+
+try:
+ import fusion as purefusion
+except ImportError:
+ pass
def get_volume(module, fusion):
@@ -166,28 +207,30 @@ def extract_current_haps(volume):
def create_volume(module, fusion):
"""Create Volume"""
-
- size = parse_number_with_metric_suffix(module, module.params["size"])
-
+ id = None
if not module.check_mode:
display_name = module.params["display_name"] or module.params["name"]
volume_api_instance = purefusion.VolumesApi(fusion)
+ source_link = get_source_link_from_parameters(module.params)
volume = purefusion.VolumePost(
- size=size,
+ size=None # when cloning a volume, size is not required
+ if source_link
+ else parse_number_with_metric_suffix(module, module.params["size"]),
storage_class=module.params["storage_class"],
placement_group=module.params["placement_group"],
name=module.params["name"],
display_name=display_name,
protection_policy=module.params["protection_policy"],
+ source_link=source_link,
)
op = volume_api_instance.create_volume(
volume,
tenant_name=module.params["tenant"],
tenant_space_name=module.params["tenant_space"],
)
- await_operation(fusion, op)
-
- return True
+ res_op = await_operation(fusion, op)
+ id = res_op.result.resource.id
+ return True, id
def update_host_access_policies(module, current, patches):
@@ -273,6 +316,17 @@ def update_protection_policy(module, current, patches):
patches.append(patch)
+def update_source_link(module, fusion, current, patches):
+ source_link = get_source_link_from_parameters(module.params)
+ if source_link is not None and (
+ current.source is None or current.source.self_link != source_link
+ ):
+ patch = purefusion.VolumePatch(
+ source_link=purefusion.NullableString(source_link)
+ )
+ patches.append(patch)
+
+
def apply_patches(module, fusion, patches):
volume_api_instance = purefusion.VolumesApi(fusion)
for patch in patches:
@@ -313,6 +367,7 @@ def update_volume(module, fusion):
update_storage_class(module, current, patches)
update_placement_group(module, current, patches)
update_host_access_policies(module, current, patches)
+ update_source_link(module, fusion, current, patches)
elif module.params["state"] == "absent" and not current.destroyed:
update_size(module, current, patches)
update_protection_policy(module, current, patches)
@@ -320,6 +375,7 @@ def update_volume(module, fusion):
update_storage_class(module, current, patches)
update_placement_group(module, current, patches)
update_host_access_policies(module, current, patches)
+ update_source_link(module, fusion, current, patches)
update_destroyed(module, current, patches)
if not module.check_mode:
@@ -355,16 +411,46 @@ def eradicate_volume(module, fusion):
return True
+def get_source_link_from_parameters(params):
+ tenant = params["tenant"]
+ tenant_space = params["tenant_space"]
+ volume = params["source_volume"]
+ snapshot = params["source_snapshot"]
+ volume_snapshot = params["source_volume_snapshot"]
+ if (
+ tenant is None or tenant_space is None
+ ): # should not happen as those parameters are always required by the ansible module
+ return None
+ if volume is not None:
+ return f"/tenants/{tenant}/tenant-spaces/{tenant_space}/volumes/{volume}"
+ if snapshot is not None and volume_snapshot is not None:
+ return f"/tenants/{tenant}/tenant-spaces/{tenant_space}/snapshots/{snapshot}/volume-snapshots/{volume_snapshot}"
+ return None
+
+
def validate_arguments(module, volume):
"""Validates most argument conditions and possible unacceptable argument combinations"""
state = module.params["state"]
if state == "present" and not volume:
- module.fail_on_missing_params(["placement_group", "storage_class", "size"])
+ module.fail_on_missing_params(["placement_group", "storage_class"])
+
+ if (
+ module.params["size"] is None
+ and module.params["source_volume"] is None
+ and module.params["source_snapshot"] is None
+ ):
+ module.fail_json(
+ msg="Either `size`, `source_volume` or `source_snapshot` parameter is required when creating a volume."
+ )
if module.params["state"] == "absent" and (
module.params["host_access_policies"]
- or (volume and volume.host_access_policies)
+ or (
+ module.params["host_access_policies"] is None
+ and volume
+ and volume.host_access_policies
+ )
):
module.fail_json(
msg=(
@@ -378,7 +464,7 @@ def validate_arguments(module, volume):
msg="'eradicate: true' cannot be used together with 'state: present'"
)
- if module.params["size"]:
+ if module.params["size"] is not None:
size = parse_number_with_metric_suffix(module, module.params["size"])
if size < 1048576 or size > 4503599627370496: # 1MB to 4PB
module.fail_json(
@@ -412,6 +498,9 @@ def main():
eradicate=dict(type="bool", default=False),
state=dict(type="str", default="present", choices=["absent", "present"]),
size=dict(type="str"),
+ source_volume=dict(type="str"),
+ source_snapshot=dict(type="str"),
+ source_volume_snapshot=dict(type="str"),
)
)
@@ -419,9 +508,22 @@ def main():
"placement_group": "storage_class",
}
+ mutually_exclusive = [
+ # a new volume cannot be based on a volume and a snapshot at the same time
+ # also, when cloning a volume, size of original volume is used
+ ("source_volume", "source_snapshot", "size"),
+ ]
+
+ required_together = [
+ # when creating a volume from snapshot, we need to know both snapshot name and snapshot volume name
+ ("source_snapshot", "source_volume_snapshot"),
+ ]
+
module = AnsibleModule(
argument_spec,
required_by=required_by,
+ mutually_exclusive=mutually_exclusive,
+ required_together=required_together,
supports_check_mode=True,
)
fusion = setup_fusion(module)
@@ -436,12 +538,19 @@ def main():
module.exit_json(changed=False)
changed = False
+ id = None
+ if volume is not None:
+ id = volume.id
if state == "present" and not volume:
- changed = changed | create_volume(module, fusion)
+ changed, id = create_volume(module, fusion)
# volume might exist even if soft-deleted, so we still have to update it
changed = changed | update_volume(module, fusion)
if module.params["eradicate"]:
changed = changed | eradicate_volume(module, fusion)
+ module.exit_json(changed=changed)
+
+ if id is not None:
+ module.exit_json(changed=changed, id=id)
module.exit_json(changed=changed)
diff --git a/ansible_collections/purestorage/fusion/test/config.yaml b/ansible_collections/purestorage/fusion/test/config.yaml
new file mode 100644
index 000000000..9e402bda7
--- /dev/null
+++ b/ansible_collections/purestorage/fusion/test/config.yaml
@@ -0,0 +1,2 @@
+modules:
+ python_requires: ">=3.6"
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_api_client.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_api_client.py
index 77f753656..295c62bd6 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_api_client.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_api_client.py
@@ -147,7 +147,19 @@ def test_api_client_create(m_im_api, current_clients):
api_obj = MagicMock()
api_obj.list_api_clients = MagicMock(return_value=current_clients)
api_obj.get_api_client = MagicMock(side_effect=purefusion.rest.ApiException)
- api_obj.create_api_client = MagicMock()
+ api_obj.create_api_client = MagicMock(
+ return_value=FakeApiClient(
+ "321321",
+ "self_link_value",
+ "client_test",
+ "client_test",
+ "apikey:name:test",
+ "321321",
+ 321321,
+ 321321,
+ "321321",
+ )
+ )
api_obj.delete_api_client = MagicMock()
m_im_api.return_value = api_obj
@@ -156,6 +168,7 @@ def test_api_client_create(m_im_api, current_clients):
fusion_api_client.main()
assert exc.value.changed is True
+ assert exc.value.id == "321321"
# check api was called correctly
api_obj.list_api_clients.assert_called_once_with()
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_array.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_array.py
index 0343bb1dc..6af1e1136 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_array.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_array.py
@@ -22,6 +22,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -46,6 +47,7 @@ def module_args():
"region": "region1",
"availability_zone": "az1",
"appliance_id": "23984573498573",
+ "apartment_id": "76586785687",
"host_name": "array_1",
"hardware_type": "flash-array-x",
"maintenance_mode": False,
@@ -65,7 +67,7 @@ def current_array(module_args):
"region": module_args["region"],
"availability_zone": module_args["availability_zone"],
"appliance_id": module_args["appliance_id"],
- "apartment_id": "76586785687",
+ "apartment_id": module_args["apartment_id"],
"host_name": module_args["host_name"],
"hardware_type": module_args["hardware_type"],
"maintenance_mode": module_args["maintenance_mode"],
@@ -332,7 +334,7 @@ def test_array_create(m_array_api, m_op_api, hw_type, main_m, unav_m, module_arg
"region": module_args["region"],
"availability_zone": module_args["availability_zone"],
"appliance_id": module_args["appliance_id"],
- "apartment_id": "76586785687",
+ "apartment_id": module_args["apartment_id"],
"host_name": module_args["host_name"],
"hardware_type": module_args["hardware_type"],
"maintenance_mode": not module_args[
@@ -364,6 +366,7 @@ def test_array_create(m_array_api, m_op_api, hw_type, main_m, unav_m, module_arg
fusion_array.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_array.assert_called_with(
@@ -378,6 +381,7 @@ def test_array_create(m_array_api, m_op_api, hw_type, main_m, unav_m, module_arg
host_name=module_args["host_name"],
name=module_args["name"],
appliance_id=module_args["appliance_id"],
+ apartment_id=module_args["apartment_id"],
),
availability_zone_name=module_args["availability_zone"],
region_name=module_args["region"],
@@ -429,7 +433,7 @@ def test_array_create_without_display_name(m_array_api, m_op_api, module_args):
"region": module_args["region"],
"availability_zone": module_args["availability_zone"],
"appliance_id": module_args["appliance_id"],
- "apartment_id": "76586785687",
+ "apartment_id": module_args["apartment_id"],
"host_name": module_args["host_name"],
"hardware_type": module_args["hardware_type"],
"maintenance_mode": not module_args["maintenance_mode"],
@@ -457,6 +461,7 @@ def test_array_create_without_display_name(m_array_api, m_op_api, module_args):
fusion_array.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_array.assert_called_with(
@@ -471,6 +476,7 @@ def test_array_create_without_display_name(m_array_api, m_op_api, module_args):
host_name=module_args["host_name"],
name=module_args["name"],
appliance_id=module_args["appliance_id"],
+ apartment_id=module_args["apartment_id"],
),
availability_zone_name=module_args["availability_zone"],
region_name=module_args["region"],
@@ -554,6 +560,7 @@ def test_array_create_exception(
host_name=module_args["host_name"],
name=module_args["name"],
appliance_id=module_args["appliance_id"],
+ apartment_id=module_args["apartment_id"],
),
availability_zone_name=module_args["availability_zone"],
region_name=module_args["region"],
@@ -583,7 +590,7 @@ def test_array_create_second_exception(
"region": module_args["region"],
"availability_zone": module_args["availability_zone"],
"appliance_id": module_args["appliance_id"],
- "apartment_id": "76586785687",
+ "apartment_id": module_args["apartment_id"],
"host_name": module_args["host_name"],
"hardware_type": module_args["hardware_type"],
"maintenance_mode": not module_args["maintenance_mode"],
@@ -623,6 +630,7 @@ def test_array_create_second_exception(
host_name=module_args["host_name"],
name=module_args["name"],
appliance_id=module_args["appliance_id"],
+ apartment_id=module_args["apartment_id"],
),
availability_zone_name=module_args["availability_zone"],
region_name=module_args["region"],
@@ -667,6 +675,7 @@ def test_array_create_op_fails(m_array_api, m_op_api, module_args):
host_name=module_args["host_name"],
name=module_args["name"],
appliance_id=module_args["appliance_id"],
+ apartment_id=module_args["apartment_id"],
),
availability_zone_name=module_args["availability_zone"],
region_name=module_args["region"],
@@ -687,7 +696,7 @@ def test_array_create_second_op_fails(m_array_api, m_op_api, module_args):
"region": module_args["region"],
"availability_zone": module_args["availability_zone"],
"appliance_id": module_args["appliance_id"],
- "apartment_id": "76586785687",
+ "apartment_id": module_args["apartment_id"],
"host_name": module_args["host_name"],
"hardware_type": module_args["hardware_type"],
"maintenance_mode": not module_args["maintenance_mode"],
@@ -729,6 +738,7 @@ def test_array_create_second_op_fails(m_array_api, m_op_api, module_args):
host_name=module_args["host_name"],
name=module_args["name"],
appliance_id=module_args["appliance_id"],
+ apartment_id=module_args["apartment_id"],
),
availability_zone_name=module_args["availability_zone"],
region_name=module_args["region"],
@@ -787,6 +797,7 @@ def test_array_create_op_exception(
host_name=module_args["host_name"],
name=module_args["name"],
appliance_id=module_args["appliance_id"],
+ apartment_id=module_args["apartment_id"],
),
availability_zone_name=module_args["availability_zone"],
region_name=module_args["region"],
@@ -816,7 +827,7 @@ def test_array_create_second_op_exception(
"region": module_args["region"],
"availability_zone": module_args["availability_zone"],
"appliance_id": module_args["appliance_id"],
- "apartment_id": "76586785687",
+ "apartment_id": module_args["apartment_id"],
"host_name": module_args["host_name"],
"hardware_type": module_args["hardware_type"],
"maintenance_mode": not module_args["maintenance_mode"],
@@ -858,6 +869,7 @@ def test_array_create_second_op_exception(
host_name=module_args["host_name"],
name=module_args["name"],
appliance_id=module_args["appliance_id"],
+ apartment_id=module_args["apartment_id"],
),
availability_zone_name=module_args["availability_zone"],
region_name=module_args["region"],
@@ -899,6 +911,7 @@ def test_array_update(m_array_api, m_op_api, module_args, current_array):
fusion_array.main()
assert exc.value.changed
+ assert exc.value.id == current_array["id"]
# check api was called correctly
api_obj.get_array.assert_called_with(
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_az.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_az.py
index c49f958a2..d19e41827 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_az.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_az.py
@@ -22,6 +22,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -139,6 +140,7 @@ def test_az_create(m_az_api, m_op_api):
fusion_az.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
api_obj.get_region.get_availability_zone(
availability_zone_name=module_args["name"],
@@ -186,6 +188,7 @@ def test_az_create_without_display_name(m_az_api, m_op_api):
fusion_az.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
api_obj.get_region.get_availability_zone(
availability_zone_name=module_args["name"],
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_hap.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_hap.py
index 6491c71da..258ca2034 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_hap.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_hap.py
@@ -23,6 +23,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -295,6 +296,7 @@ def test_hap_create(m_hap_api, m_op_api, module_args, current_hap_list):
fusion_hap.main()
assert exc.value.changed is True
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.list_host_access_policies.assert_called_once_with()
@@ -341,6 +343,7 @@ def test_hap_create_without_display_name(
fusion_hap.main()
assert exc.value.changed is True
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.list_host_access_policies.assert_called_once_with()
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_info.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_info.py
index 784b550cd..c542cddc0 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_info.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_info.py
@@ -847,6 +847,7 @@ RESP_VS = purefusion.VolumeSnapshotList(
@patch.dict(os.environ, {"TZ": "UTC"})
+@patch.dict(os.environ, {"LC_TIME": "en_US.utf8"})
@patch("fusion.DefaultApi")
@patch("fusion.IdentityManagerApi")
@patch("fusion.ProtectionPoliciesApi")
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_nig.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_nig.py
index 3a7b7ca5c..e8a2eb0ac 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_nig.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_nig.py
@@ -22,6 +22,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -236,6 +237,7 @@ def test_nig_create(m_nig_api, m_op_api):
fusion_nig.main()
assert exc.value.changed is True
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_network_interface_group.assert_called_once_with(
@@ -299,6 +301,7 @@ def test_nig_create_without_display_name(m_nig_api, m_op_api):
fusion_nig.main()
assert exc.value.changed is True
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_network_interface_group.assert_called_once_with(
@@ -362,6 +365,7 @@ def test_nig_create_without_gateway(m_nig_api, m_op_api):
fusion_nig.main()
assert exc.value.changed is True
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_network_interface_group.assert_called_once_with(
@@ -631,6 +635,7 @@ def test_nig_update(m_nig_api, m_op_api):
fusion_nig.main()
assert exc.value.changed is True
+ assert exc.value.id == current_nig.id
# check api was called correctly
api_obj.get_network_interface_group.assert_called_once_with(
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_pg.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_pg.py
index 2f0601e12..2a9419a8e 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_pg.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_pg.py
@@ -20,6 +20,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
AnsibleExitJson,
AnsibleFailJson,
OperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -221,6 +222,7 @@ def test_pg_create_ok(pg_api_init, op_api_init, module_args_present):
with pytest.raises(AnsibleExitJson) as excinfo:
fusion_pg.main()
assert excinfo.value.changed
+ assert excinfo.value.id == FAKE_RESOURCE_ID
pg_mock.get_placement_group.assert_called_with(
tenant_name="tenant1",
@@ -265,6 +267,7 @@ def test_pg_create_without_display_name_ok(
with pytest.raises(AnsibleExitJson) as excinfo:
fusion_pg.main()
assert excinfo.value.changed
+ assert excinfo.value.id == FAKE_RESOURCE_ID
pg_mock.get_placement_group.assert_called_with(
tenant_name="tenant1",
@@ -450,6 +453,7 @@ def test_pg_create_triggers_update_ok(pg_api_init, op_api_init):
with pytest.raises(AnsibleExitJson) as excinfo:
fusion_pg.main()
assert excinfo.value.changed
+ assert excinfo.value.id == FAKE_RESOURCE_ID
pg_mock.get_placement_group.assert_has_calls(
[
@@ -946,6 +950,7 @@ def test_pg_update_ok(pg_api_init, op_api_init, test_case):
with pytest.raises(AnsibleExitJson) as excinfo:
fusion_pg.main()
assert excinfo.value.changed
+ assert excinfo.value.id == test_case["current_state"].id
pg_mock.get_placement_group.assert_called_with(
tenant_name="tenant1",
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_pp.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_pp.py
index 519caea40..359d4ca7e 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_pp.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_pp.py
@@ -20,6 +20,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
AnsibleExitJson,
AnsibleFailJson,
OperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -39,7 +40,7 @@ basic.AnsibleModule.fail_json = fail_json
def module_args_present():
return {
"name": "protection_policy1",
- "local_rpo": 43,
+ "local_rpo": "1H43M",
"local_retention": "2H",
"state": "present",
"issuer_id": "ABCD1234",
@@ -181,6 +182,7 @@ def test_pp_create_ok(pp_api_init, op_api_init, module_args_present):
with pytest.raises(AnsibleExitJson) as excinfo:
fusion_pp.main()
assert excinfo.value.changed
+ assert excinfo.value.id == FAKE_RESOURCE_ID
pp_mock.get_protection_policy.assert_called_with(
protection_policy_name="protection_policy1"
@@ -190,7 +192,7 @@ def test_pp_create_ok(pp_api_init, op_api_init, module_args_present):
name="protection_policy1",
display_name="some_display_name",
objectives=[
- purefusion.RPO(type="RPO", rpo="PT43M"),
+ purefusion.RPO(type="RPO", rpo="PT103M"),
purefusion.Retention(type="Retention", after="PT120M"),
],
)
@@ -220,6 +222,7 @@ def test_pp_create_without_display_name_ok(
with pytest.raises(AnsibleExitJson) as excinfo:
fusion_pp.main()
assert excinfo.value.changed
+ assert excinfo.value.id == FAKE_RESOURCE_ID
pp_mock.get_protection_policy.assert_called_with(
protection_policy_name="protection_policy1"
@@ -229,7 +232,7 @@ def test_pp_create_without_display_name_ok(
name="protection_policy1",
display_name="protection_policy1",
objectives=[
- purefusion.RPO(type="RPO", rpo="PT43M"),
+ purefusion.RPO(type="RPO", rpo="PT103M"),
purefusion.Retention(type="Retention", after="PT120M"),
],
)
@@ -274,7 +277,7 @@ def test_pp_create_exception(
name="protection_policy1",
display_name="protection_policy1",
objectives=[
- purefusion.RPO(type="RPO", rpo="PT43M"),
+ purefusion.RPO(type="RPO", rpo="PT103M"),
purefusion.Retention(type="Retention", after="PT120M"),
],
)
@@ -310,7 +313,7 @@ def test_pp_create_op_fails(pp_api_init, op_api_init, module_args_present):
name="protection_policy1",
display_name="protection_policy1",
objectives=[
- purefusion.RPO(type="RPO", rpo="PT43M"),
+ purefusion.RPO(type="RPO", rpo="PT103M"),
purefusion.Retention(type="Retention", after="PT120M"),
],
)
@@ -333,7 +336,7 @@ def test_pp_delete_ok(pp_api_init, op_api_init, module_args_absent):
display_name="protection_policy1_display_name",
self_link="test_self_link",
objectives=[
- purefusion.RPO(type="RPO", rpo="PT43M"),
+ purefusion.RPO(type="RPO", rpo="PT103M"),
purefusion.Retention(type="Retention", after="PT120M"),
],
)
@@ -385,7 +388,7 @@ def test_pp_delete_exception(
display_name="protection_policy1_display_name",
self_link="test_self_link",
objectives=[
- purefusion.RPO(type="RPO", rpo="PT43M"),
+ purefusion.RPO(type="RPO", rpo="PT103M"),
purefusion.Retention(type="Retention", after="PT120M"),
],
)
@@ -425,7 +428,7 @@ def test_pp_delete_op_fails(pp_api_init, op_api_init, module_args_absent):
display_name="protection_policy1_display_name",
self_link="test_self_link",
objectives=[
- purefusion.RPO(type="RPO", rpo="PT43M"),
+ purefusion.RPO(type="RPO", rpo="PT103M"),
purefusion.Retention(type="Retention", after="PT120M"),
],
)
@@ -459,7 +462,7 @@ def test_pp_present_not_changed(pp_api_init, op_api_init):
module_args = {
"name": "protection_policy1",
"display_name": "some_display_name",
- "local_rpo": 43,
+ "local_rpo": "43M",
"local_retention": "2H",
"state": "present",
"issuer_id": "ABCD1234",
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ra.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ra.py
index 6456fa7d7..d8cac74a5 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ra.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ra.py
@@ -20,6 +20,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
AnsibleExitJson,
AnsibleFailJson,
OperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -330,6 +331,7 @@ def test_ra_create_ok(ra_api_init, im_api_init, op_api_init, args_and_scope):
with pytest.raises(AnsibleExitJson) as excinfo:
fusion_ra.main()
assert excinfo.value.changed
+ assert excinfo.value.id == FAKE_RESOURCE_ID
ra_mock.list_role_assignments.assert_called_with(
role_name=module_args["role"], principal="principal1"
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_region.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_region.py
index 6b13adecf..42d14d56e 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_region.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_region.py
@@ -22,6 +22,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -126,6 +127,7 @@ def test_region_create(m_region_api, m_op_api):
fusion_region.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_region.assert_called_once_with(region_name=module_args["name"])
@@ -168,6 +170,7 @@ def test_region_create_without_display_name(m_region_api, m_op_api):
fusion_region.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_region.assert_called_once_with(region_name=module_args["name"])
@@ -354,6 +357,7 @@ def test_region_update(m_region_api, m_op_api):
fusion_region.main()
assert exc.value.changed
+ assert exc.value.id == current_region["id"]
# check api was called correctly
api_obj.get_region.assert_called_once_with(region_name=module_args["name"])
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_sc.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_sc.py
index 1a2db191c..4d44e7fcb 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_sc.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_sc.py
@@ -22,6 +22,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -167,6 +168,7 @@ def test_sc_create(
fusion_sc.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_storage_class.assert_called_once_with(
@@ -224,6 +226,7 @@ def test_sc_create_without_display_name(m_sc_api, m_op_api):
fusion_sc.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_storage_class.assert_called_once_with(
@@ -608,6 +611,7 @@ def test_sc_update(m_sc_api, m_op_api):
fusion_sc.main()
assert exc.value.changed
+ assert exc.value.id == current_sc["id"]
# check api was called correctly
api_obj.get_storage_class.assert_called_once_with(
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_se.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_se.py
index a071190db..9d9559c12 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_se.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_se.py
@@ -22,6 +22,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -285,6 +286,7 @@ def test_se_create_iscsi(m_se_api, m_op_api, module_args):
fusion_se.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_storage_endpoint.assert_called_once_with(
@@ -341,6 +343,7 @@ def test_se_create_cbs_azure_iscsi(m_se_api, m_op_api, module_args):
fusion_se.main()
assert exc.value.changed is True
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_storage_endpoint.assert_called_once_with(
@@ -395,6 +398,7 @@ def test_se_create_without_display_name(m_se_api, m_op_api, module_args):
fusion_se.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_storage_endpoint.assert_called_once_with(
@@ -610,6 +614,7 @@ def test_se_update(m_se_api, m_op_api, module_args, current_se):
fusion_se.main()
assert exc.value.changed
+ assert exc.value.id == current_se["id"]
# check api was called correctly
api_obj.get_storage_endpoint.assert_called_once_with(
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ss.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ss.py
index d784b1a52..f1514b8e6 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ss.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ss.py
@@ -22,6 +22,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -139,6 +140,7 @@ def test_ss_create(m_ss_api, m_op_api):
fusion_ss.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_storage_service.assert_called_once_with(
@@ -186,6 +188,7 @@ def test_ss_create_without_display_name(m_ss_api, m_op_api):
fusion_ss.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_storage_service.assert_called_once_with(
@@ -434,6 +437,7 @@ def test_ss_update(m_ss_api, m_op_api):
fusion_ss.main()
assert exc.value.changed
+ assert exc.value.id == current_ss["id"]
# check api was called correctly
api_obj.get_storage_service.assert_called_once_with(
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_tenant.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_tenant.py
index bb0521b01..11cd71171 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_tenant.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_tenant.py
@@ -22,6 +22,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -126,6 +127,7 @@ def test_tenant_create(m_tenant_api, m_op_api):
fusion_tenant.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_tenant.assert_called_once_with(tenant_name=module_args["name"])
@@ -169,6 +171,7 @@ def test_tenant_create_without_display_name(m_tenant_api, m_op_api):
fusion_tenant.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_tenant.assert_called_once_with(tenant_name=module_args["name"])
@@ -359,6 +362,7 @@ def test_tenant_update(m_tenant_api, m_op_api):
fusion_tenant.main()
assert exc.value.changed
+ assert exc.value.id == current_tenant["id"]
# check api was called correctly
api_obj.get_tenant.assert_called_once_with(tenant_name=module_args["name"])
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ts.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ts.py
index 0d9cbb25a..0e1260858 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ts.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_ts.py
@@ -22,6 +22,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
FailedOperationMock,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -138,6 +139,7 @@ def test_ts_create(m_ts_api, m_op_api):
fusion_ts.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_tenant_space.assert_called_once_with(
@@ -186,6 +188,7 @@ def test_ts_create_without_display_name(m_ts_api, m_op_api):
fusion_ts.main()
assert exc.value.changed
+ assert exc.value.id == FAKE_RESOURCE_ID
# check api was called correctly
api_obj.get_tenant_space.assert_called_once_with(
@@ -399,6 +402,7 @@ def test_ts_update(m_ts_api, m_op_api):
fusion_ts.main()
assert exc.value.changed
+ assert exc.value.id == current_ts["id"]
# check api was called correctly
api_obj.get_tenant_space.assert_called_once_with(
diff --git a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_volume.py b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_volume.py
index 592bda32e..43f69666e 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/test_fusion_volume.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/test_fusion_volume.py
@@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-from unittest.mock import MagicMock, patch
+from unittest.mock import MagicMock, call, patch
import fusion as purefusion
import pytest
@@ -23,6 +23,7 @@ from ansible_collections.purestorage.fusion.tests.functional.utils import (
AnsibleFailJson,
OperationMock,
SuccessfulOperationMock,
+ FAKE_RESOURCE_ID,
exit_json,
fail_json,
set_module_args,
@@ -126,7 +127,7 @@ def destroyed_volume(volume):
),
(
"size",
- "missing required arguments: size",
+ "Either `size`, `source_volume` or `source_snapshot` parameter is required when creating a volume.",
),
],
)
@@ -164,6 +165,18 @@ def test_module_fails_on_missing_parameters(
{"size": "1K"},
"Size is not within the required range",
),
+ (
+ {"source_volume": "vol_name"},
+ "parameters are mutually exclusive: source_volume|source_snapshot|size",
+ ),
+ (
+ {"source_snapshot": "snap_name"},
+ "parameters are mutually exclusive: source_volume|source_snapshot|size",
+ ),
+ (
+ {"source_volume_snapshot": "vol_snap_name"},
+ "parameters are required together: source_snapshot, source_volume_snapshot",
+ ),
],
)
def test_module_fails_on_incorrect_parameters(
@@ -216,6 +229,8 @@ def test_volume_create_successfully(mock_volumes_api, mock_operations_api, modul
with pytest.raises(AnsibleExitJson) as exception:
fusion_volume.main()
assert exception.value.changed is True
+ assert exception.value.id == FAKE_RESOURCE_ID
+
volumes_api.get_volume.assert_called_with(
volume_name=module_args["name"],
tenant_name=module_args["tenant"],
@@ -238,6 +253,90 @@ def test_volume_create_successfully(mock_volumes_api, mock_operations_api, modul
@patch("fusion.OperationsApi")
@patch("fusion.VolumesApi")
+def test_volume_create_from_volume_successfully(
+ mock_volumes_api, mock_operations_api, module_args
+):
+ del module_args["size"]
+ module_args["source_volume"] = "source_volume_name"
+
+ operations_api = purefusion.OperationsApi()
+ volumes_api = purefusion.VolumesApi()
+ volumes_api.get_volume = MagicMock(side_effect=purefusion.rest.ApiException)
+ volumes_api.create_volume = MagicMock(return_value=OperationMock(1))
+ operations_api.get_operation = MagicMock(return_value=SuccessfulOperationMock)
+ mock_volumes_api.return_value = volumes_api
+ mock_operations_api.return_value = operations_api
+ set_module_args(module_args)
+ # run module
+ with pytest.raises(AnsibleExitJson) as exception:
+ fusion_volume.main()
+ assert exception.value.changed is True
+ assert exception.value.id == FAKE_RESOURCE_ID
+ volumes_api.get_volume.assert_called_with(
+ volume_name=module_args["name"],
+ tenant_name=module_args["tenant"],
+ tenant_space_name=module_args["tenant_space"],
+ )
+ volumes_api.create_volume.assert_called_once_with(
+ purefusion.VolumePost(
+ source_link=f"/tenants/{module_args['tenant']}/tenant-spaces/{module_args['tenant_space']}/volumes/{module_args['source_volume']}",
+ storage_class=module_args["storage_class"],
+ placement_group=module_args["placement_group"],
+ name=module_args["name"],
+ display_name=module_args["display_name"],
+ protection_policy=module_args["protection_policy"],
+ ),
+ tenant_name=module_args["tenant"],
+ tenant_space_name=module_args["tenant_space"],
+ )
+ operations_api.get_operation.assert_called_once_with(1)
+
+
+@patch("fusion.OperationsApi")
+@patch("fusion.VolumesApi")
+def test_volume_create_from_volume_snapshot_successfully(
+ mock_volumes_api, mock_operations_api, module_args
+):
+ del module_args["size"]
+ module_args["source_snapshot"] = "source_snapshot_name"
+ module_args["source_volume_snapshot"] = "source_volume_snapshot_name"
+
+ operations_api = purefusion.OperationsApi()
+ volumes_api = purefusion.VolumesApi()
+ volumes_api.get_volume = MagicMock(side_effect=purefusion.rest.ApiException)
+ volumes_api.create_volume = MagicMock(return_value=OperationMock(1))
+ operations_api.get_operation = MagicMock(return_value=SuccessfulOperationMock)
+ mock_volumes_api.return_value = volumes_api
+ mock_operations_api.return_value = operations_api
+ set_module_args(module_args)
+ # run module
+ with pytest.raises(AnsibleExitJson) as exception:
+ fusion_volume.main()
+ assert exception.value.changed is True
+ assert exception.value.id == FAKE_RESOURCE_ID
+ volumes_api.get_volume.assert_called_with(
+ volume_name=module_args["name"],
+ tenant_name=module_args["tenant"],
+ tenant_space_name=module_args["tenant_space"],
+ )
+ volumes_api.create_volume.assert_called_once_with(
+ purefusion.VolumePost(
+ source_link=f"/tenants/{module_args['tenant']}/tenant-spaces/{module_args['tenant_space']}/snapshots/"
+ f"{module_args['source_snapshot']}/volume-snapshots/{module_args['source_volume_snapshot']}",
+ storage_class=module_args["storage_class"],
+ placement_group=module_args["placement_group"],
+ name=module_args["name"],
+ display_name=module_args["display_name"],
+ protection_policy=module_args["protection_policy"],
+ ),
+ tenant_name=module_args["tenant"],
+ tenant_space_name=module_args["tenant_space"],
+ )
+ operations_api.get_operation.assert_called_once_with(1)
+
+
+@patch("fusion.OperationsApi")
+@patch("fusion.VolumesApi")
def test_volume_create_without_display_name_successfully(
mock_volumes_api, mock_operations_api, module_args
):
@@ -254,6 +353,7 @@ def test_volume_create_without_display_name_successfully(
with pytest.raises(AnsibleExitJson) as exception:
fusion_volume.main()
assert exception.value.changed is True
+ assert exception.value.id == FAKE_RESOURCE_ID
volumes_api.get_volume.assert_called_with(
volume_name=module_args["name"],
tenant_name=module_args["tenant"],
@@ -399,6 +499,7 @@ def test_volume_update_with_state_present_executed_correctly(
with pytest.raises(AnsibleExitJson) as exception:
fusion_volume.main()
assert exception.value.changed is True
+ assert exception.value.id == volume["id"]
volumes_api.get_volume.assert_called_with(
volume_name=module_args["name"],
tenant_name=module_args["tenant"],
@@ -447,6 +548,7 @@ def test_volume_update_with_state_absent_executed_correctly(
with pytest.raises(AnsibleExitJson) as exception:
fusion_volume.main()
assert exception.value.changed is True
+ assert exception.value.id == volume["id"]
volumes_api.get_volume.assert_called_with(
volume_name=module_args["name"],
tenant_name=module_args["tenant"],
@@ -713,3 +815,47 @@ def test_volume_delete_operation_throws_exception(
tenant_space_name=absent_module_args["tenant_space"],
)
operations_api.get_operation.assert_called_once_with(2)
+
+
+@patch("fusion.OperationsApi")
+@patch("fusion.VolumesApi")
+def test_module_updates_on_empty_array_of_haps(
+ mock_volumes_api, mock_operations_api, module_args, volume
+):
+ volumes_api = purefusion.VolumesApi()
+ operations_api = purefusion.OperationsApi()
+ volumes_api.get_volume = MagicMock(return_value=purefusion.Volume(**volume))
+ volumes_api.update_volume = MagicMock(return_value=OperationMock(1))
+ operations_api.get_operation = MagicMock(return_value=SuccessfulOperationMock)
+ mock_operations_api.return_value = operations_api
+ mock_volumes_api.return_value = volumes_api
+ module_args.update({"state": "absent", "host_access_policies": []})
+ set_module_args(module_args)
+ # run module
+ with pytest.raises(AnsibleExitJson) as exception:
+ fusion_volume.main()
+ assert exception.value.changed is True
+ assert exception.value.id == volume["id"]
+ volumes_api.get_volume.assert_called_with(
+ volume_name=module_args["name"],
+ tenant_name=module_args["tenant"],
+ tenant_space_name=module_args["tenant_space"],
+ )
+ volumes_api.update_volume.assert_has_calls(
+ [
+ call(
+ purefusion.VolumePatch(
+ host_access_policies=purefusion.NullableString(",".join([]))
+ ),
+ volume_name=volume["name"],
+ tenant_name=volume["tenant"],
+ tenant_space_name=volume["tenant_space"],
+ ),
+ call(
+ purefusion.VolumePatch(destroyed=purefusion.NullableBoolean(True)),
+ volume_name=volume["name"],
+ tenant_name=volume["tenant"],
+ tenant_space_name=volume["tenant_space"],
+ ),
+ ]
+ )
diff --git a/ansible_collections/purestorage/fusion/tests/functional/utils.py b/ansible_collections/purestorage/fusion/tests/functional/utils.py
index 24d6f0328..53e501bc0 100644
--- a/ansible_collections/purestorage/fusion/tests/functional/utils.py
+++ b/ansible_collections/purestorage/fusion/tests/functional/utils.py
@@ -7,6 +7,11 @@ from dataclasses import dataclass
from ansible.module_utils import basic
from ansible.module_utils.common.text.converters import to_bytes
+from ansible_collections.purestorage.fusion.tests.helpers import (
+ OperationResultsDict,
+)
+
+FAKE_RESOURCE_ID = "fake-id-12345"
@dataclass
@@ -20,6 +25,9 @@ class OperationMock:
self.status = "Pending"
elif success:
self.status = "Succeeded"
+ self.result = OperationResultsDict(
+ {"resource": OperationResultsDict({"id": FAKE_RESOURCE_ID})}
+ )
else:
self.status = "Failed"
self.id = id
@@ -30,6 +38,9 @@ class SuccessfulOperationMock:
Mock object for successful operation. This object is returned by mocked Operation API if the operation was successful.
"""
+ result = OperationResultsDict(
+ {"resource": OperationResultsDict({"id": FAKE_RESOURCE_ID})}
+ )
status = "Succeeded"
@@ -65,6 +76,10 @@ class AnsibleExitJson(Exception):
return self.kwargs["changed"]
@property
+ def id(self):
+ return self.kwargs["id"]
+
+ @property
def fusion_info(self):
return self.kwargs["fusion_info"] if "fusion_info" in self.kwargs else None
diff --git a/ansible_collections/purestorage/fusion/tests/helpers.py b/ansible_collections/purestorage/fusion/tests/helpers.py
index 40d98cf0e..76d51b6f7 100644
--- a/ansible_collections/purestorage/fusion/tests/helpers.py
+++ b/ansible_collections/purestorage/fusion/tests/helpers.py
@@ -27,3 +27,11 @@ class ApiExceptionsMockGenerator:
def create_not_found():
status = HTTPStatus.NOT_FOUND
return purefusion.rest.ApiException(status=status, reason=status.phrase)
+
+
+class OperationResultsDict(dict):
+ """dot.notation access to dictionary attributes"""
+
+ __getattr__ = dict.get
+ __setattr__ = dict.__setitem__
+ __delattr__ = dict.__delitem__
diff --git a/ansible_collections/purestorage/fusion/tests/unit/mocks/operation_mock.py b/ansible_collections/purestorage/fusion/tests/unit/mocks/operation_mock.py
index 99487ddfa..a3a70c67d 100644
--- a/ansible_collections/purestorage/fusion/tests/unit/mocks/operation_mock.py
+++ b/ansible_collections/purestorage/fusion/tests/unit/mocks/operation_mock.py
@@ -8,6 +8,9 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
from enum import Enum
+from ansible_collections.purestorage.fusion.tests.helpers import (
+ OperationResultsDict,
+)
class OperationStatus(str, Enum):
@@ -18,7 +21,16 @@ class OperationStatus(str, Enum):
class OperationMock:
- def __init__(self, id, status, retry_in=1):
+ def __init__(
+ self,
+ id,
+ status,
+ result=OperationResultsDict(
+ {"resource": OperationResultsDict({"id": "fake-id"})}
+ ),
+ retry_in=1,
+ ):
self.id = id
self.status = status
self.retry_in = retry_in
+ self.result = result
diff --git a/ansible_collections/purestorage/fusion/tests/unit/module_utils/test_parsing.py b/ansible_collections/purestorage/fusion/tests/unit/module_utils/test_parsing.py
index 7e2a1cc78..230d0ff01 100644
--- a/ansible_collections/purestorage/fusion/tests/unit/module_utils/test_parsing.py
+++ b/ansible_collections/purestorage/fusion/tests/unit/module_utils/test_parsing.py
@@ -7,13 +7,12 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
+import pytest
from ansible_collections.purestorage.fusion.plugins.module_utils.parsing import (
- parse_number_with_metric_suffix,
parse_minutes,
+ parse_number_with_metric_suffix,
)
-import pytest
-
class MockException(Exception):
pass
@@ -83,17 +82,37 @@ def test_parsing_invalid_number():
def test_parsing_valid_time_period():
module = MockModule()
+ assert parse_minutes(module, "0") == 0
+ assert parse_minutes(module, "00") == 0
+ assert parse_minutes(module, "00M") == 0
assert parse_minutes(module, "10") == 10
- assert parse_minutes(module, "2h") == 120
- assert parse_minutes(module, "2H") == 120
+ assert parse_minutes(module, "015") == 15
+ assert parse_minutes(module, "0023") == 23
+ assert parse_minutes(module, "0H10M") == 10
+ assert parse_minutes(module, "2h") == 2 * 60
+ assert parse_minutes(module, "2H") == 2 * 60
+ assert parse_minutes(module, "02h") == 2 * 60
+ assert parse_minutes(module, "02H") == 2 * 60
+ assert parse_minutes(module, "002h") == 2 * 60
+ assert parse_minutes(module, "002H") == 2 * 60
+ assert parse_minutes(module, "0D10H10M") == 10 * 60 + 10
assert parse_minutes(module, "14D") == 14 * 24 * 60
+ assert parse_minutes(module, "014D") == 14 * 24 * 60
+ assert parse_minutes(module, "0000014D") == 14 * 24 * 60
assert parse_minutes(module, "1W") == 7 * 24 * 60
+ assert parse_minutes(module, "01W") == 7 * 24 * 60
+ assert parse_minutes(module, "01Y0H10M") == 365 * 24 * 60 + 10
assert parse_minutes(module, "12Y") == 12 * 365 * 24 * 60
+ assert parse_minutes(module, "012Y") == 12 * 365 * 24 * 60
assert (
parse_minutes(module, "10Y20W30D40H50M")
== 10 * 365 * 24 * 60 + 20 * 7 * 24 * 60 + 30 * 24 * 60 + 40 * 60 + 50
)
assert (
+ parse_minutes(module, "010Y20W30D40H50M")
+ == 10 * 365 * 24 * 60 + 20 * 7 * 24 * 60 + 30 * 24 * 60 + 40 * 60 + 50
+ )
+ assert (
parse_minutes(module, "10Y20W30D40H")
== 10 * 365 * 24 * 60 + 20 * 7 * 24 * 60 + 30 * 24 * 60 + 40 * 60
)
@@ -110,6 +129,10 @@ def test_parsing_valid_time_period():
assert parse_minutes(module, "40H50M") == 40 * 60 + 50
assert parse_minutes(module, "30D50M") == 30 * 24 * 60 + 50
assert parse_minutes(module, "20W40H") == 20 * 7 * 24 * 60 + 40 * 60
+ assert (
+ parse_minutes(module, "01W000010D10H10M")
+ == 7 * 24 * 60 + 10 * 24 * 60 + 10 * 60 + 10
+ )
def test_parsing_invalid_time_period():
@@ -123,16 +146,8 @@ def test_parsing_invalid_time_period():
with pytest.raises(MockException):
assert parse_minutes(module, "1V")
with pytest.raises(MockException):
- assert parse_minutes(module, "0M")
- with pytest.raises(MockException):
- assert parse_minutes(module, "0H10M")
- with pytest.raises(MockException):
- assert parse_minutes(module, "0H10M")
+ assert parse_minutes(module, "1v")
with pytest.raises(MockException):
- assert parse_minutes(module, "0D10H10M")
+ assert parse_minutes(module, "10M2H")
with pytest.raises(MockException):
- assert parse_minutes(module, "01W10D10H10M")
- with pytest.raises(MockException):
- assert parse_minutes(module, "01Y0H10M")
- with pytest.raises(MockException):
- assert parse_minutes(module, "1V")
+ assert parse_minutes(module, "0H10M01Y")
diff --git a/ansible_collections/purestorage/fusion/tests/unit/modules/test_fusion_az.py b/ansible_collections/purestorage/fusion/tests/unit/modules/test_fusion_az.py
index a384506d8..ee300638e 100644
--- a/ansible_collections/purestorage/fusion/tests/unit/modules/test_fusion_az.py
+++ b/ansible_collections/purestorage/fusion/tests/unit/modules/test_fusion_az.py
@@ -81,7 +81,9 @@ class TestCreateAZ:
azone, region_name=module_params["region"]
)
await_operation_mock.assert_called_once_with(fusion_mock, op)
- moduleMock.exit_json.assert_called_once_with(changed=True)
+ moduleMock.exit_json.assert_called_once_with(
+ changed=True, id=op.result.resource.id
+ )
@patch(f"{current_module}.fusion_az.purefusion.AvailabilityZonesApi.__new__")
@patch(f"{current_module}.fusion_az.await_operation")
@@ -113,7 +115,7 @@ class TestCreateAZ:
# Assertions
mock_az_api_obj.create_availability_zone.assert_not_called()
await_operation_mock.assert_not_called()
- moduleMock.exit_json.assert_called_once_with(changed=True)
+ moduleMock.exit_json.assert_called_once_with(changed=True, id=None)
@patch(f"{current_module}.fusion_az.purefusion.AvailabilityZonesApi.__new__")
@patch(f"{current_module}.fusion_az.await_operation")
@@ -151,7 +153,9 @@ class TestCreateAZ:
azone, region_name=module_params["region"]
)
await_operation_mock.assert_called_once_with(fusion_mock, op)
- moduleMock.exit_json.assert_called_once_with(changed=True)
+ moduleMock.exit_json.assert_called_once_with(
+ changed=True, id=op.result.resource.id
+ )
@patch(f"{current_module}.fusion_az.purefusion.AvailabilityZonesApi.__new__")
@patch(f"{current_module}.fusion_az.await_operation")