diff options
Diffstat (limited to 'ansible_collections/purestorage')
14 files changed, 628 insertions, 27 deletions
diff --git a/ansible_collections/purestorage/flashblade/CHANGELOG.rst b/ansible_collections/purestorage/flashblade/CHANGELOG.rst index 13b845abd..a673257d2 100644 --- a/ansible_collections/purestorage/flashblade/CHANGELOG.rst +++ b/ansible_collections/purestorage/flashblade/CHANGELOG.rst @@ -5,6 +5,18 @@ Purestorage.Flashblade Release Notes .. contents:: Topics +v1.17.0 +======= + +Minor Changes +------------- + +- purefb_bucket - Add support for strict 17a-4 WORM compliance. +- purefb_connect - Increase Fan-In and Fan-Out maximums +- purefb_fs - Add ``group_ownership`` parameter from Purity//FB 4.4.0. +- purefb_info - Show array network access policy from Purity//FB 4.4.0 +- purefb_policy - Add support for network access policies from Purity//FB 4.4.0 + v1.16.0 ======= @@ -225,7 +237,6 @@ v1.6.0 Minor Changes ------------- -- purefb_virtualhost - New module to manage API Clients - purefb_ad - New module to manage Active Directory Account - purefb_eula - New module to sign EULA - purefb_info - Add Active Directory, Kerberos and Object Store Account information @@ -234,6 +245,7 @@ Minor Changes - purefb_s3user - Add access policy option to user creation - purefb_timeout - Add module to set GUI idle timeout - purefb_userpolicy - New module to manage object store user access policies +- purefb_virtualhost - New module to manage API Clients - purefb_virtualhost - New module to manage Object Store Virtual Hosts New Modules @@ -292,12 +304,12 @@ Minor Changes Bugfixes -------- -- purefb_policy - Resolve multiple issues related to incorrect use of timezones - purefb_connect - Ensure changing encryption status on array connection is performed correctly - purefb_connect - Fix breaking change created in purity_fb SDK 1.9.2 for deletion of array connections - purefb_connect - Hide target array API token - purefb_ds - Ensure updating directory service configurations completes correctly - purefb_info - Fix issue getting array info when encrypted connection exists +- purefb_policy - Resolve multiple issues related to incorrect use of timezones New Modules ----------- diff --git a/ansible_collections/purestorage/flashblade/FILES.json b/ansible_collections/purestorage/flashblade/FILES.json index d7b39dbda..8f3e38a96 100644 --- a/ansible_collections/purestorage/flashblade/FILES.json +++ b/ansible_collections/purestorage/flashblade/FILES.json @@ -519,6 +519,13 @@ "format": 1 }, { + "name": "changelogs/fragments/274_fan_in.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1c0e28b50aa1fe8a6325de6ea6dd486019ec307ccb8fa84ef543b8b2f00baef6", + "format": 1 + }, + { "name": "changelogs/fragments/81_purefb_fs_new_options.yaml", "ftype": "file", "chksum_type": "sha256", @@ -610,6 +617,13 @@ "format": 1 }, { + "name": "changelogs/fragments/273_add_nap.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "498d161b9e61c95f2fcf64618d3304c5a46b8e16828306cf2ae585e504b01dc6", + "format": 1 + }, + { "name": "changelogs/fragments/191_add_quota_info.yaml", "ftype": "file", "chksum_type": "sha256", @@ -666,6 +680,13 @@ "format": 1 }, { + "name": "changelogs/fragments/271_add_worm.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e4a187b7e2f9bc1b81cf60415317dd8f966b214d113f476f2bc18900de54c6a9", + "format": 1 + }, + { "name": "changelogs/fragments/101_fix_policy_and_timezone_error.yaml", "ftype": "file", "chksum_type": "sha256", @@ -715,6 +736,13 @@ "format": 1 }, { + "name": "changelogs/fragments/270_add_go.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "81731ce510a6e2cd5947f609ba78ea396e19bbf3e44f36f49ae5c8991f0ca425", + "format": 1 + }, + { "name": "changelogs/fragments/113_policy_cleanup.yaml", "ftype": "file", "chksum_type": "sha256", @@ -725,14 +753,14 @@ "name": "changelogs/changelog.yaml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "58ab80ddfd28321e4c9f245810097a8efbcd09898e013b3a83e650d2dd8440ed", + "chksum_sha256": "b2c3c0bab9ffe396ec0afe29c985db329e969ec0389ebc5c41e601f93f597e72", "format": 1 }, { "name": "changelogs/.plugin-cache.yaml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "74f8ee5c9b2c27b9b655d822e47443fc68975023c10a6e58c08dc4b925c61bb3", + "chksum_sha256": "ef9e016e5b4618c4d5057f035eaf5d7be9c626f2c4265bd3f34430e1561ad6da", "format": 1 }, { @@ -928,7 +956,7 @@ "name": "plugins/modules/purefb_policy.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9c6abe4b8cf5db61cd7a27db057f8d2f28cf0d2ec2bf9b398cf3f9eba68bb0e1", + "chksum_sha256": "94b94ab9aa31fac3e8e42024a9605dbab36d7b4b86f6030f0bcf6f00d5283f43", "format": 1 }, { @@ -984,7 +1012,7 @@ "name": "plugins/modules/purefb_connect.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "820c57b48e107ef852e6b2665c65ef76d67ffcde916cb21a368dcdae8e1e23e4", + "chksum_sha256": "eedb065fa37a7cffe50c2c7cc1ef9717f4ce3aa76ec4334cfb6ee420e44e0260", "format": 1 }, { @@ -1117,7 +1145,7 @@ "name": "plugins/modules/purefb_fs.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "2438642ad2a6ce605587eb84e0573010449ce0710d601cbf337dfa4690d7b736", + "chksum_sha256": "22af8016c0b29191ade09778e7d6279287ac866130b3fc212f85909f4a8bc099", "format": 1 }, { @@ -1166,7 +1194,7 @@ "name": "plugins/modules/purefb_info.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "b6dc24aac2c4733f7f37f0901a70fc3a9679cb06994d1407ba85f92bcc110d53", + "chksum_sha256": "70d3b538db7be7ea4b8faa6762d7e978120c112a5c4d81954425ae807ea6f91c", "format": 1 }, { @@ -1187,7 +1215,7 @@ "name": "plugins/modules/purefb_bucket.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "11e6a2e0aa40ab4f7e50a4c2be3dfd17363e094b8ac126b5ad042c4d65c16055", + "chksum_sha256": "507922eadc0bc73ec2a2e0c2e7cdda348203f4bb6b09f1120370c775a64f2bf8", "format": 1 }, { @@ -1383,7 +1411,7 @@ "name": "CHANGELOG.rst", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "de7d63a6d1d411e66f64971129b4630faaca228eb0a8348f261034aab83faa04", + "chksum_sha256": "cc4723553b99c762a97c9f06c61cae678c1c5cce90ffc7cc43202e23bf4885ed", "format": 1 } ], diff --git a/ansible_collections/purestorage/flashblade/MANIFEST.json b/ansible_collections/purestorage/flashblade/MANIFEST.json index 2af712175..cb9fde10c 100644 --- a/ansible_collections/purestorage/flashblade/MANIFEST.json +++ b/ansible_collections/purestorage/flashblade/MANIFEST.json @@ -2,7 +2,7 @@ "collection_info": { "namespace": "purestorage", "name": "flashblade", - "version": "1.16.0", + "version": "1.17.0", "authors": [ "Pure Storage Ansible Team <pure-ansible-team@purestorage.com>" ], @@ -30,7 +30,7 @@ "name": "FILES.json", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "14b510daea00c6bbcbf0a5bcfff2c45937740e569c86fedeb64970968dc4eecc", + "chksum_sha256": "985b106cb8f390a1084cc8fd39b7d5ff1d5ec674b068edc67fd1e9108b41e6cc", "format": 1 }, "format": 1 diff --git a/ansible_collections/purestorage/flashblade/changelogs/.plugin-cache.yaml b/ansible_collections/purestorage/flashblade/changelogs/.plugin-cache.yaml index c99d4477d..bcb6c205c 100644 --- a/ansible_collections/purestorage/flashblade/changelogs/.plugin-cache.yaml +++ b/ansible_collections/purestorage/flashblade/changelogs/.plugin-cache.yaml @@ -256,4 +256,4 @@ plugins: strategy: {} test: {} vars: {} -version: 1.16.0 +version: 1.17.0 diff --git a/ansible_collections/purestorage/flashblade/changelogs/changelog.yaml b/ansible_collections/purestorage/flashblade/changelogs/changelog.yaml index eaeb07ed3..71acf6b6a 100644 --- a/ansible_collections/purestorage/flashblade/changelogs/changelog.yaml +++ b/ansible_collections/purestorage/flashblade/changelogs/changelog.yaml @@ -168,6 +168,20 @@ releases: - 266_bucket_fix.yaml - 268_multi-chassis-lag.yaml release_date: '2024-02-27' + 1.17.0: + changes: + minor_changes: + - purefb_bucket - Add support for strict 17a-4 WORM compliance. + - purefb_connect - Increase Fan-In and Fan-Out maximums + - purefb_fs - Add ``group_ownership`` parameter from Purity//FB 4.4.0. + - purefb_info - Show array network access policy from Purity//FB 4.4.0 + - purefb_policy - Add support for network access policies from Purity//FB 4.4.0 + fragments: + - 270_add_go.yaml + - 271_add_worm.yaml + - 273_add_nap.yaml + - 274_fan_in.yaml + release_date: '2024-04-01' 1.3.0: changes: bugfixes: @@ -210,7 +224,6 @@ releases: 1.4.0: changes: bugfixes: - - purefb_policy - Resolve multiple issues related to incorrect use of timezones - purefb_connect - Ensure changing encryption status on array connection is performed correctly - purefb_connect - Fix breaking change created in purity_fb SDK 1.9.2 for deletion @@ -218,6 +231,7 @@ releases: - purefb_connect - Hide target array API token - purefb_ds - Ensure updating directory service configurations completes correctly - purefb_info - Fix issue getting array info when encrypted connection exists + - purefb_policy - Resolve multiple issues related to incorrect use of timezones minor_changes: - purefb_banner - Module to manage the GUI and SSH login message - purefb_certgrp - Module to manage FlashBlade Certificate Groups @@ -300,7 +314,6 @@ releases: 1.6.0: changes: minor_changes: - - purefb_virtualhost - New module to manage API Clients - purefb_ad - New module to manage Active Directory Account - purefb_eula - New module to sign EULA - purefb_info - Add Active Directory, Kerberos and Object Store Account information @@ -309,6 +322,7 @@ releases: - purefb_s3user - Add access policy option to user creation - purefb_timeout - Add module to set GUI idle timeout - purefb_userpolicy - New module to manage object store user access policies + - purefb_virtualhost - New module to manage API Clients - purefb_virtualhost - New module to manage Object Store Virtual Hosts fragments: - 127_add_eula.yaml diff --git a/ansible_collections/purestorage/flashblade/changelogs/fragments/270_add_go.yaml b/ansible_collections/purestorage/flashblade/changelogs/fragments/270_add_go.yaml new file mode 100644 index 000000000..d875db5ab --- /dev/null +++ b/ansible_collections/purestorage/flashblade/changelogs/fragments/270_add_go.yaml @@ -0,0 +1,2 @@ +minor_changes: + - purefb_fs - Add ``group_ownership`` parameter from Purity//FB 4.4.0. diff --git a/ansible_collections/purestorage/flashblade/changelogs/fragments/271_add_worm.yaml b/ansible_collections/purestorage/flashblade/changelogs/fragments/271_add_worm.yaml new file mode 100644 index 000000000..379975be3 --- /dev/null +++ b/ansible_collections/purestorage/flashblade/changelogs/fragments/271_add_worm.yaml @@ -0,0 +1,2 @@ +minor_changes: + - purefb_bucket - Add support for strict 17a-4 WORM compliance. diff --git a/ansible_collections/purestorage/flashblade/changelogs/fragments/273_add_nap.yaml b/ansible_collections/purestorage/flashblade/changelogs/fragments/273_add_nap.yaml new file mode 100644 index 000000000..998de322e --- /dev/null +++ b/ansible_collections/purestorage/flashblade/changelogs/fragments/273_add_nap.yaml @@ -0,0 +1,3 @@ +minor_changes: + - purefb_info - Show array network access policy from Purity//FB 4.4.0 + - purefb_policy - Add support for network access policies from Purity//FB 4.4.0 diff --git a/ansible_collections/purestorage/flashblade/changelogs/fragments/274_fan_in.yaml b/ansible_collections/purestorage/flashblade/changelogs/fragments/274_fan_in.yaml new file mode 100644 index 000000000..719fca54b --- /dev/null +++ b/ansible_collections/purestorage/flashblade/changelogs/fragments/274_fan_in.yaml @@ -0,0 +1,2 @@ +minor_changes: + - purefb_connect - Increase Fan-In and Fan-Out maximums diff --git a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_bucket.py b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_bucket.py index 27cd7e317..11c8be479 100644 --- a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_bucket.py +++ b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_bucket.py @@ -118,13 +118,32 @@ options: description: - If set to true, adding bucket policies that grant public access to a bucket is not allowed. type: bool - version_added: 1.15.0 + version_added: '1.15.0' block_public_access: description: - If set to true, access to a bucket with a public policy is restricted to only authenticated users within the account that bucket belongs to. type: bool - version_added: 1.15.0 + version_added: '1.15.0' + eradication_mode: + description: + - The eradication mode of the bucket. + type: str + choices: [ "permission-based", "retention-based" ] + version_added: '1.17.0' + manual_eradication: + description: + - The manual eradication status of the bucket. If false, the bucket cannot be eradicated after + it has been destroyed, unless it is empty. If true, the bucket can be eradicated. + type: bool + version_added: '1.17.0' + eradication_delay: + description: + - Minimum eradication delay in days. Automatically eradicate destroyed buckets after + the delay time passes unless automatic eradication is delayed due to other configuration values. + - Valid values are integer days from 1 to 30. Default is 1. + type: int + version_added: '1.17.0' extends_documentation_fragment: - purestorage.flashblade.purestorage.fb """ @@ -194,11 +213,13 @@ from ansible_collections.purestorage.flashblade.plugins.module_utils.purefb impo ) +SEC_PER_DAY = 86400000 MIN_REQUIRED_API_VERSION = "1.5" VERSIONING_VERSION = "1.9" VSO_VERSION = "2.5" QUOTA_VERSION = "2.8" MODE_VERSION = "2.12" +WORM_VERSION = "2.13" def get_s3acc(module, blade): @@ -354,6 +375,30 @@ def create_bucket(module, blade): msg="Failed to set Public Access config correctly for bucket {0}. " "Error: {1}".format(module.params["name"], res.errors[0].message) ) + if WORM_VERSION in api_version and module.params["eradication_mode"]: + if not module.params["eradication_delay"]: + module.params["eradication_delay"] = SEC_PER_DAY + else: + module.params["eradication_delay"] = ( + module.params["eradication_delay"] * SEC_PER_DAY + ) + if not module.params["manual_eradication"]: + module.params["manual_eradication"] = "disabled" + else: + module.params["manual_eradication"] = "enabled" + worm = BucketPatch( + eradication_config=flashblade.BucketEradicationConfig( + manual_eradication=module.params["manual_eradication"], + eradication_mode=module.params["eradication_mode"], + eradication_delay=module.params["eradication_delay"], + ) + ) + res = bladev2.patch_buckets(bucket=worm, names=[module.params["name"]]) + if res.status_code != 200: + module.warn( + msg="Failed to set Bucket Eradication config correctly for bucket {0}. " + "Error: {1}".format(module.params["name"], res.errors[0].message) + ) module.exit_json(changed=changed) @@ -416,6 +461,7 @@ def update_bucket(module, blade, bucket): """Update Bucket""" changed = False change_pac = False + change_worm = False bladev2 = get_system(module) bucket_detail = list(bladev2.get_buckets(names=[module.params["name"]]).items)[0] api_version = blade.api_version.list_versions().versions @@ -520,7 +566,52 @@ def update_bucket(module, blade, bucket): msg="Failed to update Public Access config correctly for bucket {0}. " "Error: {1}".format(module.params["name"], res.errors[0].message) ) - module.exit_json(changed=(changed or change_pac)) + if WORM_VERSION in api_version: + current_worm = { + "eradication_delay": bucket_detail.eradication_config.eradication_delay, + "manual_eradication": bucket_detail.eradication_config.manual_eradication, + "eradication_mode": bucket_detail.eradication_config.eradication_mode, + } + if module.params["eradication_delay"] is None: + new_delay = current_worm["eradication_delay"] + else: + new_delay = module.params["eradication_delay"] * SEC_PER_DAY + if module.params["manual_eradication"] is None: + new_manual = current_worm["manual_eradication"] + else: + if module.params["manual_eradication"]: + new_manual = "enabled" + else: + new_manual = "disabled" + if ( + module.params["eradication_mode"] + and module.params["eradication_mode"] != current_worm["eradication_mode"] + ): + new_mode = module.params["eradication_mode"] + else: + new_mode = current_worm["eradication_mode"] + new_worm = { + "eradication_delay": new_delay, + "manual_eradication": new_manual, + "eradication_mode": new_mode, + } + if current_worm != new_worm: + change_worm = True + worm = BucketPatch( + public_access_config=flashblade.BucketEradicationConfig( + eradication_delay=new_worm.eradication_delay, + manual_eradication=new_worm.manual_eradication, + eradication_mode=new_worm.eradication_mode, + ) + ) + if change_worm and not module.check_mode: + res = bladev2.patch_buckets(bucket=worm, names=[module.params["name"]]) + if res.status_code != 200: + module.fail_json( + msg="Failed to update Eradication config correctly for bucket {0}. " + "Error: {1}".format(module.params["name"], res.errors[0].message) + ) + module.exit_json(changed=(changed or change_pac or change_worm)) def eradicate_bucket(module, blade): @@ -564,6 +655,11 @@ def main(): default="absent", choices=["enabled", "suspended", "absent"] ), state=dict(default="present", choices=["present", "absent"]), + eradication_delay=dict(type="int"), + eradication_mode=dict( + type="str", choices=["permission-based", "retention-based"] + ), + manual_eradication=dict(type="bool"), ) ) @@ -575,6 +671,12 @@ def main(): if not HAS_PYPURECLIENT: module.fail_json(msg="py-pure-client sdk is required to support VSO mode") + if ( + module.params["eradication_delay"] + and not 30 >= module.params["eradication_delay"] >= 1 + ): + module.fail_json(msg="Eradication Delay must be between 1 and 30 days.") + state = module.params["state"] blade = get_blade(module) api_version = blade.api_version.list_versions().versions diff --git a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_connect.py b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_connect.py index 846351453..23e54845c 100644 --- a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_connect.py +++ b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_connect.py @@ -138,8 +138,8 @@ from ansible_collections.purestorage.flashblade.plugins.module_utils.purefb impo ) -FAN_IN_MAXIMUM = 1 -FAN_OUT_MAXIMUM = 3 +FAN_IN_MAXIMUM = 5 +FAN_OUT_MAXIMUM = 5 MIN_REQUIRED_API_VERSION = "1.9" THROTTLE_API_VERSION = "2.3" @@ -215,7 +215,7 @@ def create_connection(module, blade): remote_conn_cnt = ( remote_system.array_connections.list_array_connections().pagination_info.total_item_count ) - if remote_conn_cnt == FAN_IN_MAXIMUM: + if remote_conn_cnt >= FAN_IN_MAXIMUM: module.fail_json( msg="Remote array {0} already connected to {1} other array. Fan-In not supported".format( remote_array, remote_conn_cnt @@ -244,7 +244,7 @@ def create_connection(module, blade): def create_v2_connection(module, blade): """Create connection between REST 2 capable arrays""" changed = True - if blade.get_array_connections().total_item_count == FAN_OUT_MAXIMUM: + if blade.get_array_connections().total_item_count >= FAN_OUT_MAXIMUM: module.fail_json( msg="FlashBlade fan-out maximum of {0} already reached".format( FAN_OUT_MAXIMUM @@ -262,7 +262,7 @@ def create_v2_connection(module, blade): ) remote_array = list(remote_system.get_arrays().items)[0].name remote_conn_cnt = remote_system.get_array_connections().total_item_count - if remote_conn_cnt == FAN_IN_MAXIMUM: + if remote_conn_cnt >= FAN_IN_MAXIMUM: module.fail_json( msg="Remote array {0} already connected to {1} other array. Fan-In not supported".format( remote_array, remote_conn_cnt diff --git a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_fs.py b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_fs.py index 8d332e8b7..81c12d4b7 100644 --- a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_fs.py +++ b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_fs.py @@ -195,11 +195,17 @@ options: version_added: "1.12.0" continuous_availability: description: - - Deifines if the file system will be continuously available during + - Defines if the file system will be continuously available during disruptive scenarios such as network disruption, blades failover, etc type: bool default: true version_added: "1.15.0" + group_ownership: + description: + - The group ownership for new files and directories in a file system + type: str + choices: [ 'creator', 'parent-directory' ] + version_added: "1.17.0" extends_documentation_fragment: - purestorage.flashblade.purestorage.fb """ @@ -314,6 +320,7 @@ MULTIPROTOCOL_API_VERSION = "1.11" EXPORT_POLICY_API_VERSION = "2.3" SMB_POLICY_API_VERSION = "2.10" CA_API_VERSION = "2.12" +GOWNER_API_VERSION = "2.13" def get_fs(module, blade): @@ -567,6 +574,21 @@ def create_fs(module, blade): res.errors[0].message, ) ) + if GOWNER_API_VERSION in api_version and module.params["group_ownership"]: + go_attr = FileSystemPatch( + group_ownership=module.params["group_ownership"] + ) + res = system.patch_file_systems( + names=[module.params["name"]], file_system=go_attr + ) + if res.status_code != 200: + module.fail_json( + msg="Filesystem {0} created, but failed to set group ownership" + "Error: {1}".format( + module.params["name"], + res.errors[0].message, + ) + ) module.exit_json(changed=changed) @@ -911,8 +933,29 @@ def modify_fs(module, blade): res.errors[0].message, ) ) + if GOWNER_API_VERSION in api_version: + change_go = False + if module.params["group_ownership"] != current_fs.group_ownership: + change_go = True + if not module.check_mode: + go_attr = FileSystemPatch( + group_ownership=module.params["group_ownership"] + ) + res = system.patch_file_systems( + names=[module.params["name"]], file_system=go_attr + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to modify group ownership for " + "filesystem {0}. Error: {1}".format( + module.params["name"], + res.errors[0].message, + ) + ) - module.exit_json(changed=(changed or change_export or change_share or change_ca)) + module.exit_json( + changed=(changed or change_export or change_share or change_ca or change_go) + ) def _delete_fs(module, blade): @@ -1057,6 +1100,7 @@ def main(): smb_aclmode=dict( type="str", default="shared", choices=["shared", "native"] ), + group_ownership=dict(choices=["creator", "parent-directory"]), policy_state=dict(default="present", choices=["present", "absent"]), state=dict(default="present", choices=["present", "absent"]), delete_link=dict(default=False, type="bool"), diff --git a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_info.py b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_info.py index 033312e82..418dacd5d 100644 --- a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_info.py +++ b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_info.py @@ -111,6 +111,7 @@ BUCKET_API_VERSION = "2.8" SMB_CLIENT_API_VERSION = "2.10" SPACE_API_VERSION = "2.11" PUBLIC_API_VERSION = "2.12" +NAP_API_VERSION = "2.13" def _millisecs_to_time(millisecs): @@ -218,6 +219,10 @@ def generate_default_dict(module, blade): default_info["security_update"] = getattr( blade_info, "security_update", None ) + if NAP_API_VERSION in api_version: + default_info["network_access_protocol"] = getattr( + blade_info.network_access_policy, "name", "None" + ) return default_info diff --git a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py index ebe70aa48..36ffee997 100644 --- a/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py +++ b/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py @@ -52,7 +52,7 @@ options: - Type of policy default: snapshot type: str - choices: [ snapshot, access, nfs, smb_share, smb_client ] + choices: [ snapshot, access, nfs, smb_share, smb_client, network ] version_added: "1.9.0" account: description: @@ -344,6 +344,14 @@ options: type: str default: "" version_added: '1.14.0' + interfaces: + description: + - Specifies which product interfaces the network access policy rule + applies to, whether it is permitting or denying access. + type: list + elements: str + choices: [ "management-ssh", "management-rest-api", "management-web-ui", "snmp", "local-network-superuser-password-access" ] + version_added: '1.17.0' extends_documentation_fragment: - purestorage.flashblade.purestorage.fb """ @@ -546,6 +554,8 @@ try: SmbClientPolicyRule, SmbClientPolicy, ObjectStoreAccessPolicyPost, + NetworkAccessPolicy, + NetworkAccessPolicyRule, ) except ImportError: HAS_PYPURECLIENT = False @@ -577,6 +587,7 @@ NFS_POLICY_API_VERSION = "2.3" NFS_RENAME_API_VERSION = "2.4" SMB_POLICY_API_VERSION = "2.10" SMB_ENCRYPT_API_VERSION = "2.11" +NET_POLICY_API_VERSION = "2.13" def _convert_to_millisecs(hour): @@ -1065,6 +1076,51 @@ def create_smb_client_policy(module, blade): module.exit_json(changed=changed) +def create_network_access_policy(module, blade): + """Create Network Access Policy""" + changed = True + versions = blade.api_version.list_versions().versions + if not module.check_mode: + res = blade.post_network_access_policies(names=[module.params["name"]]) + if res.status_code != 200: + module.fail_json( + msg="Failed to create network access policy {0}.Error: {1}".format( + module.params["name"], res.errors[0].message + ) + ) + if not module.params["enabled"]: + res = blade.patch_network_access_policies( + policy=SmbClientPolicy(enabled=False), names=[module.params["name"]] + ) + if res.status_code != 200: + blade.delete_network_access_policies(names=[module.params["name"]]) + module.fail_json( + msg="Failed to create network access policy {0}.Error: {1}".format( + module.params["name"], res.errors[0].message + ) + ) + if not module.params["client"]: + module.fail_json(msg="client is required to create a new rule") + else: + rule = NetworkAccessPolicyRule( + client=module.params["client"], + effect=module.params["effect"], + interfaces=module.params["interfaces"], + ) + res = blade.post_network_access_policies_rules( + policy_names=[module.params["name"]], + rule=rule, + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to rule for policy {0}. Error: {1}".format( + module.params["name"], + res.errors[0].message, + ) + ) + module.exit_json(changed=changed) + + def update_smb_client_policy(module, blade): """Update SMB Client Policy Rule""" @@ -1341,6 +1397,268 @@ def delete_nfs_policy(module, blade): module.exit_json(changed=changed) +def update_network_access_policy(module, blade): + """Update Networkk Access Policy Rule""" + + changed = False + if module.params["client"]: + current_policy_rule = blade.get_network_access_policies_rules( + policy_names=[module.params["name"]], + filter="client='" + module.params["client"] + "'", + ) + if ( + current_policy_rule.status_code == 200 + and current_policy_rule.total_item_count == 0 + ): + rule = NetworkAccessPolicyRule( + client=module.params["client"], + effect=module.params["effect"], + interfaces=module.params["interfaces"], + ) + changed = True + if not module.check_mode: + if module.params["before_rule"]: + before_name = ( + module.params["name"] + "." + str(module.params["before_rule"]) + ) + res = blade.post_network_access_policies_rules( + policy_names=[module.params["name"]], + rule=rule, + before_rule_name=before_name, + ) + else: + res = blade.post_network_access_policies_rules( + policy_names=[module.params["name"]], + rule=rule, + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to create rule for client {0} " + "in policy {1}. Error: {2}".format( + module.params["client"], + module.params["name"], + res.errors[0].message, + ) + ) + else: + rules = list(current_policy_rule.items) + cli_count = None + done = False + if module.params["client"] == "*": + for cli in range(0, len(rules)): + if rules[cli].client == "*": + cli_count = cli + if not cli_count: + rule = NetworkAccessPolicyRule( + client=module.params["client"], + effect=module.params["effect"], + interfaces=module.params["interfaces"], + ) + done = True + changed = True + if not module.check_mode: + if module.params["before_rule"]: + res = blade.post_network_access_policies_rules( + policy_names=[module.params["name"]], + rule=rule, + before_rule_name=( + module.params["name"] + + "." + + str(module.params["before_rule"]), + ), + ) + else: + res = blade.post_network_access_policies_rules( + policy_names=[module.params["name"]], + rule=rule, + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to create rule for " + "client {0} in policy {1}. Error: {2}".format( + module.params["client"], + module.params["name"], + res.errors[0].message, + ) + ) + if not done: + old_policy_rule = rules[0] + current_rule = { + "client": sorted(old_policy_rule.client), + "effect": old_policy_rule.effect, + "interfaces": old_policy_rule.interfaces, + } + if module.params["interfaces"]: + new_interfaces = module.params["interfaces"] + else: + new_interfaces = current_rule["interfaces"] + if module.params["effect"]: + new_effect = module.params["effect"] + else: + new_effect = current_rule["effect"] + if module.params["client"]: + new_client = sorted(module.params["client"]) + else: + new_client = sorted(current_rule["client"]) + new_rule = { + "client": new_client, + "effect": new_effect, + "interfaces": new_interfaces, + } + if current_rule != new_rule: + changed = True + if not module.check_mode: + rule = NetworkAccessPolicyRule( + client=module.params["client"], + effect=module.params["effect"], + interfaces=module.params["interfaces"], + ) + res = blade.patch_network_access_policies_rules( + names=[ + module.params["name"] + "." + str(old_policy_rule.index) + ], + rule=rule, + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to update network access client rule {0}. Error: {1}".format( + module.params["name"] + + "." + + str(old_policy_rule.index), + res.errors[0].message, + ) + ) + if ( + module.params["before_rule"] + and module.params["before_rule"] != old_policy_rule.index + ): + changed = True + if not module.check_mode: + before_name = ( + module.params["name"] + + "." + + str(module.params["before_rule"]) + ) + res = blade.patch_network_access_policies_rules( + names=[ + module.params["name"] + "." + str(old_policy_rule.index) + ], + rule=NetworkAccessPolicyRule(), + before_rule_name=before_name, + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to move network access client rule {0}. Error: {1}".format( + module.params["name"] + + "." + + str(old_policy_rule.index), + res.errors[0].message, + ) + ) + current_policy = list( + blade.get_network_access_policies(names=[module.params["name"]]).items + )[0] + if current_policy.enabled != module.params["enabled"]: + changed = True + if not module.check_mode: + res = blade.patch_network_access_policies( + policy=NetworkAccessPolicy(enabled=module.params["enabled"]), + names=[module.params["name"]], + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to change state of network access policy {0}.Error: {1}".format( + module.params["name"], res.errors[0].message + ) + ) + module.exit_json(changed=changed) + + +def delete_network_access_policy(module, blade): + """Delete Network Access Policy, or Rule + + If client is provided then delete the client rule if it exists. + """ + + changed = False + policy_delete = True + if module.params["client"]: + policy_delete = False + res = blade.get_network_access_policies_rules( + policy_names=[module.params["name"]], + filter="client='" + module.params["client"] + "'", + ) + if res.status_code == 200: + if res.total_item_count == 0: + pass + elif res.total_item_count == 1: + rule = list(res.items)[0] + if module.params["client"] == rule.client: + changed = True + if not module.check_mode: + res = blade.delete_network_access_policies_rules( + names=[rule.name] + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to delete rule for client {0} in policy {1}. " + "Error: {2}".format( + module.params["client"], + module.params["name"], + res.errors[0].message, + ) + ) + else: + rules = list(res.items) + for cli in range(0, len(rules)): + if rules[cli].client == "*": + changed = True + if not module.check_mode: + res = blade.delete_network_access_policies_rules( + names=[rules[cli].name] + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to delete rule for client {0} in policy {1}. " + "Error: {2}".format( + module.params["client"], + module.params["name"], + res.errors[0].message, + ) + ) + if policy_delete: + changed = True + if not module.check_mode: + res = blade.delete_network_Access_policies(names=[module.params["name"]]) + if res.status_code != 200: + module.fail_json( + msg="Failed to delete network access policy {0}. Error: {1}".format( + module.params["name"], res.errors[0].message + ) + ) + module.exit_json(changed=changed) + + +def rename_network_access_policy(module, blade): + """Rename Network Access Policy""" + + changed = True + if not module.check_mode: + res = blade.patch_network_access_policies( + names=[module.params["name"]], + policy=NfsExportPolicy(name=module.params["rename"]), + ) + if res.status_code != 200: + module.fail_json( + msg="Failed to rename network access policy {0} to {1}. Error: {2}".format( + module.params["name"], + module.params["rename"], + res.errors[0].message, + ) + ) + module.exit_json(changed=changed) + + def rename_nfs_policy(module, blade): """Rename NFS Export Policy""" @@ -2544,7 +2862,14 @@ def main(): policy_type=dict( type="str", default="snapshot", - choices=["snapshot", "access", "nfs", "smb_share", "smb_client"], + choices=[ + "snapshot", + "access", + "nfs", + "smb_share", + "smb_client", + "network", + ], ), enabled=dict(type="bool", default=True), timezone=dict(type="str"), @@ -2635,6 +2960,17 @@ def main(): choices=["disabled", "optional", "required"], ), desc=dict(type="str", default=""), + interfaces=dict( + type="list", + elements="str", + choices=[ + "management-ssh", + "management-rest-api", + "management-web-ui", + "snmp", + "local-network-superuser-password-access", + ], + ), ) ) @@ -2644,6 +2980,7 @@ def main(): ["policy_type", "nfs", ["name"]], ["policy_type", "smb_client", ["name"]], ["policy_type", "smb_share", ["name"]], + ["policy_type", "network", ["interfaces"]], ] module = AnsibleModule( @@ -2857,6 +3194,56 @@ def main(): create_smb_share_policy(module, blade) elif state == "absent" and policy: delete_smb_share_policy(module, blade) + elif module.params["policy_type"] == "network": + if NET_POLICY_API_VERSION not in versions: + module.fail_json( + msg=( + "Minimum FlashBlade REST version required: {0}".format( + NET_POLICY_API_VERSION + ) + ) + ) + if not HAS_PYPURECLIENT: + module.fail_json(msg="py-pure-client sdk is required for this module") + blade = get_system(module) + try: + policy = list( + blade.get_network_access_policies(names=[module.params["name"]]).items + )[0] + except AttributeError: + policy = None + if module.params["rename"]: + try: + new_policy = list( + blade.get_network_access_policies( + names=[module.params["rename"]] + ).items + )[0] + except AttributeError: + new_policy = None + if policy and state == "present" and not module.params["rename"]: + if module.params["before_rule"]: + res = blade.get_network_access_policies_rules( + policy_names=[module.params["name"]], + names=[ + module.params["name"] + "." + str(module.params["before_rule"]) + ], + ) + if res.status_code != 200: + module.fail_json( + msg="Rule index {0} does not exist.".format( + module.params["before_rule"] + ) + ) + update_network_access_policy(module, blade) + elif ( + state == "present" and module.params["rename"] and policy and not new_policy + ): + rename_network_access_policy(module, blade) + elif state == "present" and not policy and not module.params["rename"]: + create_network_access_policy(module, blade) + elif state == "absent" and policy: + delete_network_access_policy(module, blade) elif SNAPSHOT_POLICY_API_VERSION in versions: if not HAS_PYPURECLIENT: module.fail_json(msg="py-pure-client sdk is required for this module") |