#!/usr/bin/python # Copyright (c) 2018, Hewlett Packard Enterprise Development LP # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later from __future__ import annotations DOCUMENTATION = r""" short_description: Manage HPE StoreServ 3PAR CPG author: - Farhan Nomani (@farhan7500) - Gautham P Hegde (@gautamphegde) description: - Create and delete CPG on HPE 3PAR. module: ss_3par_cpg attributes: check_mode: support: none diff_mode: support: none options: cpg_name: description: - Name of the CPG. type: str required: true disk_type: choices: - FC - NL - SSD description: - Specifies that physical disks must have the specified device type. type: str domain: description: - Specifies the name of the domain in which the object resides. type: str growth_increment: description: - Specifies the growth increment(in MiB, GiB or TiB) the amount of logical disk storage created on each auto-grow operation. type: str growth_limit: description: - Specifies that the autogrow operation is limited to the specified storage amount that sets the growth limit (in MiB, GiB or TiB). type: str growth_warning: description: - Specifies that the threshold (in MiB, GiB or TiB) of used logical disk space when exceeded results in a warning alert. type: str high_availability: choices: - PORT - CAGE - MAG description: - Specifies that the layout must support the failure of one port pair, one cage, or one magazine. type: str raid_type: choices: - R0 - R1 - R5 - R6 description: - Specifies the RAID type for the logical disk. type: str set_size: description: - Specifies the set size in the number of chunklets. type: int state: choices: - present - absent description: - Whether the specified CPG should exist or not. required: true type: str secure: description: - Specifies whether the certificate needs to be validated while communicating. type: bool default: false extends_documentation_fragment: - community.general.hpe3par - community.general.attributes """ EXAMPLES = r""" - name: Create CPG sample_cpg community.general.ss_3par_cpg: storage_system_ip: 10.10.10.1 storage_system_username: username storage_system_password: password state: present cpg_name: sample_cpg domain: sample_domain growth_increment: 32000 MiB growth_limit: 64000 MiB growth_warning: 48000 MiB raid_type: R6 set_size: 8 high_availability: MAG disk_type: FC secure: false - name: Delete CPG sample_cpg community.general.ss_3par_cpg: storage_system_ip: 10.10.10.1 storage_system_username: username storage_system_password: password state: absent cpg_name: sample_cpg secure: false """ RETURN = r""" """ from ansible.module_utils.basic import AnsibleModule from ansible_collections.community.general.plugins.module_utils.storage.hpe3par import hpe3par try: from hpe3par_sdk import client from hpe3parclient import exceptions HAS_3PARCLIENT = True except ImportError: HAS_3PARCLIENT = False def validate_set_size(raid_type, set_size): if raid_type: set_size_array = client.HPE3ParClient.RAID_MAP[raid_type]["set_sizes"] if set_size in set_size_array: return True return False def cpg_ldlayout_map(ldlayout_dict): if ldlayout_dict["RAIDType"] is not None and ldlayout_dict["RAIDType"]: ldlayout_dict["RAIDType"] = client.HPE3ParClient.RAID_MAP[ldlayout_dict["RAIDType"]]["raid_value"] if ldlayout_dict["HA"] is not None and ldlayout_dict["HA"]: ldlayout_dict["HA"] = getattr(client.HPE3ParClient, ldlayout_dict["HA"]) return ldlayout_dict def create_cpg( client_obj, cpg_name, domain, growth_increment, growth_limit, growth_warning, raid_type, set_size, high_availability, disk_type, ): try: if not validate_set_size(raid_type, set_size): return (False, False, f"Set size {set_size} not part of RAID set {raid_type}") if not client_obj.cpgExists(cpg_name): disk_patterns = [] if disk_type: disk_type = getattr(client.HPE3ParClient, disk_type) disk_patterns = [{"diskType": disk_type}] ld_layout = { "RAIDType": raid_type, "setSize": set_size, "HA": high_availability, "diskPatterns": disk_patterns, } ld_layout = cpg_ldlayout_map(ld_layout) if growth_increment is not None: growth_increment = hpe3par.convert_to_binary_multiple(growth_increment) if growth_limit is not None: growth_limit = hpe3par.convert_to_binary_multiple(growth_limit) if growth_warning is not None: growth_warning = hpe3par.convert_to_binary_multiple(growth_warning) optional = { "domain": domain, "growthIncrementMiB": growth_increment, "growthLimitMiB": growth_limit, "usedLDWarningAlertMiB": growth_warning, "LDLayout": ld_layout, } client_obj.createCPG(cpg_name, optional) else: return (True, False, "CPG already present") except exceptions.ClientException as e: return (False, False, f"CPG creation failed | {e}") return (True, True, f"Created CPG {cpg_name} successfully.") def delete_cpg(client_obj, cpg_name): try: if client_obj.cpgExists(cpg_name): client_obj.deleteCPG(cpg_name) else: return (True, False, "CPG does not exist") except exceptions.ClientException as e: return (False, False, f"CPG delete failed | {e}") return (True, True, f"Deleted CPG {cpg_name} successfully.") def main(): module = AnsibleModule(argument_spec=hpe3par.cpg_argument_spec(), required_together=[["raid_type", "set_size"]]) if not HAS_3PARCLIENT: module.fail_json(msg="the python hpe3par_sdk library is required (https://pypi.org/project/hpe3par_sdk)") if len(module.params["cpg_name"]) < 1 or len(module.params["cpg_name"]) > 31: module.fail_json(msg="CPG name must be at least 1 character and not more than 31 characters") storage_system_ip = module.params["storage_system_ip"] storage_system_username = module.params["storage_system_username"] storage_system_password = module.params["storage_system_password"] cpg_name = module.params["cpg_name"] domain = module.params["domain"] growth_increment = module.params["growth_increment"] growth_limit = module.params["growth_limit"] growth_warning = module.params["growth_warning"] raid_type = module.params["raid_type"] set_size = module.params["set_size"] high_availability = module.params["high_availability"] disk_type = module.params["disk_type"] secure = module.params["secure"] wsapi_url = f"https://{storage_system_ip}:8080/api/v1" try: client_obj = client.HPE3ParClient(wsapi_url, secure) except exceptions.SSLCertFailed: module.fail_json(msg="SSL Certificate Failed") except exceptions.ConnectionError: module.fail_json(msg="Connection Error") except exceptions.UnsupportedVersion: module.fail_json(msg="Unsupported WSAPI version") except Exception as e: module.fail_json(msg=f"Initializing client failed. {e}") if storage_system_username is None or storage_system_password is None: module.fail_json(msg="Storage system username or password is None") if cpg_name is None: module.fail_json(msg="CPG Name is None") # States if module.params["state"] == "present": try: client_obj.login(storage_system_username, storage_system_password) return_status, changed, msg = create_cpg( client_obj, cpg_name, domain, growth_increment, growth_limit, growth_warning, raid_type, set_size, high_availability, disk_type, ) except Exception as e: module.fail_json(msg=f"CPG create failed | {e}") finally: client_obj.logout() elif module.params["state"] == "absent": try: client_obj.login(storage_system_username, storage_system_password) return_status, changed, msg = delete_cpg(client_obj, cpg_name) except Exception as e: module.fail_json(msg=f"CPG create failed | {e}") finally: client_obj.logout() if return_status: module.exit_json(changed=changed, msg=msg) else: module.fail_json(msg=msg) if __name__ == "__main__": main()