From 7983856dd6517345f8b319012429aa97af4631f5 Mon Sep 17 00:00:00 2001 From: ABHISHEK-SINHA10 Date: Wed, 15 Jan 2025 20:38:42 +0530 Subject: [PATCH] Improved score --- .../file_tree_quota_examples.py | 3 +- .../file_user_quota_examples.py | 3 +- PyPowerStore/client.py | 8 +- PyPowerStore/configuration.py | 21 +- PyPowerStore/protection.py | 6 +- PyPowerStore/provisioning.py | 5340 ++++++++--------- 6 files changed, 2694 insertions(+), 2687 deletions(-) diff --git a/ProgrammersGuideExamples/file_tree_quota_examples.py b/ProgrammersGuideExamples/file_tree_quota_examples.py index 011b3d7..e509b3e 100644 --- a/ProgrammersGuideExamples/file_tree_quota_examples.py +++ b/ProgrammersGuideExamples/file_tree_quota_examples.py @@ -22,7 +22,8 @@ print(QUOTA) # Get treequota list -filter_dict = {"id": "eq.{0}".format(QUOTA["id"])} +quota_id = QUOTA["id"] +filter_dict = {"id": f"eq.{quota_id}"} QUOTA_LIST = CONN.provisioning.get_file_tree_quotas(filter_dict=filter_dict) print(QUOTA_LIST) diff --git a/ProgrammersGuideExamples/file_user_quota_examples.py b/ProgrammersGuideExamples/file_user_quota_examples.py index e5de3ef..9340083 100644 --- a/ProgrammersGuideExamples/file_user_quota_examples.py +++ b/ProgrammersGuideExamples/file_user_quota_examples.py @@ -21,7 +21,8 @@ print(QUOTA) # Get userquota list -filter_dict = {"id": "eq.{0}".format(QUOTA["id"])} +quota_id = QUOTA["id"] +filter_dict = {"id": f"eq.{quota_id}"} QUOTA_LIST = CONN.provisioning.get_file_user_quotas(filter_dict=filter_dict) print(QUOTA_LIST) diff --git a/PyPowerStore/client.py b/PyPowerStore/client.py index 60224ef..5e569ac 100644 --- a/PyPowerStore/client.py +++ b/PyPowerStore/client.py @@ -221,9 +221,8 @@ def fetch_response( headers.update(auth_headers) LOG.debug( - "Request's http_method: '%s' url: '%s' payload: '%s' " - "querystring: '%s' myrange: '%s'" - % (http_method, url, payload, querystring, myrange), + "Request's http_method: '%s' url: '%s' payload: '%s' querystring: '%s' myrange: '%s'" + , http_method, url, payload, querystring, myrange ) if myrange: headers["Range"] = myrange @@ -432,7 +431,8 @@ def request(self, http_method, url, payload=None, querystring=None, all_pages=No ) from exception except Timeout as exception: LOG.error(str(exception)) - raise PowerStoreException(PowerStoreException.TIMEOUT_ERROR, str(exception)) from exception + raise PowerStoreException(PowerStoreException.TIMEOUT_ERROR, str(exception) + ) from exception except OSError as exception: LOG.error(str(exception)) raise PowerStoreException(PowerStoreException.SOCKET_ERR, str(exception)) from exception diff --git a/PyPowerStore/configuration.py b/PyPowerStore/configuration.py index 69bb755..1974870 100644 --- a/PyPowerStore/configuration.py +++ b/PyPowerStore/configuration.py @@ -1426,7 +1426,8 @@ def modify_security_config(self, security_config_id, protocol_mode): :rtype: None """ LOG.info( - f"Modify security config properties: '{security_config_id}' with params '{protocol_mode}'", + f"Modify security config properties: \ + '{security_config_id}' with params '{protocol_mode}'", ) payload = {} @@ -1515,7 +1516,8 @@ def modify_destination_email_details(self, email_id, modify_parameters): :rtype : None """ LOG.info( - f"Modifying destination email properties: '{email_id}' with params '{modify_parameters}'", + f"Modifying destination email properties: \ + '{email_id}' with params '{modify_parameters}'", ) email_url = constants.MODIFY_EMAIL_URL @@ -1633,7 +1635,8 @@ def modify_smtp_config_details(self, smtp_id, modify_parameters): :rtype : None """ LOG.info( - f"Modifying SMTP configuration properties: '{smtp_id}' with params '{modify_parameters}'", + f"Modifying SMTP configuration properties: \ + '{smtp_id}' with params '{modify_parameters}'", ) smtp_url = constants.MODIFY_SMTP_URL @@ -1933,7 +1936,8 @@ def get_remote_support_contact_list(self, filter_dict=None, all_pages=None): :rtype: list[dict] """ LOG.info( - f"Getting all remote support contact with filter: '{filter_dict}' and all_pages: '{all_pages}'", + f"Getting all remote support contact with filter: \ + '{filter_dict}' and all_pages: '{all_pages}'", ) if helpers.is_foot_hill_or_higher(): querystring = helpers.prepare_querystring(constants.SELECT_ID, filter_dict) @@ -1999,7 +2003,8 @@ def modify_remote_support_contact_details( :rtype : None """ LOG.info( - f"Modifying remote support contact : '{remote_support_contact_id}' with params '{modify_parameters}'", + f"Modifying remote support contact : \ + '{remote_support_contact_id}' with params '{modify_parameters}'", ) if helpers.is_foot_hill_or_higher(): remote_support_contact_url = constants.MODIFY_REMOTE_SUPPORT_CONTACT_URL @@ -2475,7 +2480,7 @@ def get_storage_container_destination_list(self, filter_dict=None, all_pages=Non """ LOG.info( "Getting storage containers destination with filter: '%s' " - "and all_pages: %s" % (filter_dict, all_pages), + "and all_pages: %s" , filter_dict, all_pages ) querystring = helpers.prepare_querystring( constants.STORAGE_CONTAINER_DETAILS_DESTINATION_QUERY, filter_dict, @@ -2502,7 +2507,7 @@ def get_storage_container_destination_details( """ LOG.info( "Getting storage container destination details by " - "ID: '%s'" % storage_container_destination_id, + "ID: '%s'" , storage_container_destination_id ) return self.config_client.request( @@ -2536,7 +2541,7 @@ def delete_storage_container_destination(self, storage_container_destination_id) """ LOG.info( "Deleting storage container destination with " - "id: '%s'" % storage_container_destination_id, + "id: '%s'" , storage_container_destination_id, ) return self.config_client.request( constants.DELETE, diff --git a/PyPowerStore/protection.py b/PyPowerStore/protection.py index 9b48d45..6c0f331 100644 --- a/PyPowerStore/protection.py +++ b/PyPowerStore/protection.py @@ -839,7 +839,7 @@ def get_filesystem_snapshot_details_by_name( ) LOG.info( "Getting filesystem snapshot: '%s' details by " - "nasserver id: '%s'" % (snapshot_name, nas_server_id), + "nasserver id: '%s'" , snapshot_name, nas_server_id ) return self.provisioning.get_filesystem_by_name( filesystem_name=snapshot_name, nas_server_id=nas_server_id, @@ -1058,7 +1058,7 @@ def get_replication_sessions(self, filter_dict=None, all_pages=False): """ LOG.info( "Getting replication sessions with filter: '%s' and " - "all_pages: '%s'" % (filter_dict, all_pages), + "all_pages: '%s'" , filter_dict, all_pages, ) querystring = helpers.prepare_querystring(constants.SELECT_ID, filter_dict) LOG.info("Querystring: '%s'", querystring) @@ -1190,7 +1190,7 @@ def get_replication_groups(self, filter_dict=None, all_pages=False): """ LOG.info( "Getting replication groups with filter: '%s' and " - "all_pages: %s" % (filter_dict, all_pages), + "all_pages: %s" , filter_dict, all_pages, ) querystring = helpers.prepare_querystring( constants.REPLICATION_GROUP_QUERY, filter_dict, diff --git a/PyPowerStore/provisioning.py b/PyPowerStore/provisioning.py index 4bc4fb7..2df3405 100644 --- a/PyPowerStore/provisioning.py +++ b/PyPowerStore/provisioning.py @@ -1,2670 +1,2670 @@ -# Copyright: (c) 2024, Dell Technologies - -"""Collection of provisioning related functions for PowerStore""" - -from PyPowerStore.client import Client -from PyPowerStore.utils import constants, helpers - -# TODO: kept LOG as global for now will improve it to avoid overriding -LOG = helpers.get_logger(__name__) - - -class Provisioning: - """Provisioning related functionality for PowerStore.""" - - def __init__( - self, - server_ip, - username, - password, - verify, - application_type, - timeout, - enable_log=False, - port_no=None, - ): - """Initializes Provisioning Class - - :param server_ip: The array IP - :type server_ip: str - :param port_no: The port number - :type port_no: int - :param username: array username - :type username: str - :param password: array password - :type password: str - :param verify: Whether the SSL cert will be verified - :type verify: bool - :param application_type: Application Type - :type application_type: str - :param timeout: How long to wait for the server to send data before - giving up - :type timeout: float - :param enable_log: (optional) Whether to enable log or not - :type enable_log: bool - """ - global LOG - if port_no is None: - port_no = 443 - self.server_ip = server_ip + ":" + str(port_no) - self.client = Client( - username, password, verify, application_type, timeout, enable_log=enable_log, - ) - LOG = helpers.get_logger(__name__, enable_log=enable_log) - helpers.set_provisioning_obj(self) - - def get_array_version(self): - """Get the software version of this array. - - :return: software version details - :rtype: str - """ - LOG.info("Getting the software version of this array") - querystring = helpers.prepare_querystring(constants.SELECT_VERSION) - LOG.info( "Querystring: '%s'", querystring) - sw_versions = self.client.request( - constants.GET, - constants.GET_SOFTWARE_VERSION.format(self.server_ip), - payload=None, - querystring=querystring, - ) - version = None - if sw_versions and len(sw_versions) > 0: - version = sw_versions[0]["release_version"] - return version - - def create_volume( - self, - name, - size, - description=None, - volume_group_id=None, - protection_policy_id=None, - performance_policy_id=None, - app_type=None, - app_type_other=None, - appliance_id=None, - ): - """Create a volume. - - :param name: The name of the volume - :param size: The size of the volume - :param description: (optional) The description given to the volume - :param volume_group_id: (optional) The volume group ID - :param protection_policy_id: (optional) The protection policy ID - :param performance_policy_id: (optional) The performance policy ID - :param app_type: (optional) The application type - :param app_type_other: (optional) Describes application type when - app_type is set to other - :param appliance_id: (optional) The appliance ID - """ - if app_type is not None and not helpers.is_malka_or_higher(): - raise Exception( - "'app_type' parameter is supported only from " - "Powerstore version 2.1.0.0 onwards", - ) - - LOG.info( "Creating volume: '%s'", name) - payload = self._prepare_create_volume_payload( - name, - size, - description, - volume_group_id, - protection_policy_id, - performance_policy_id, - app_type, - app_type_other, - appliance_id, - ) - self.client.request( - constants.POST, constants.VOLUME_CREATE_URL.format(self.server_ip), payload, - ) - - def _prepare_create_volume_payload( - self, - name, - size, - description, - volume_group_id, - protection_policy_id, - performance_policy_id, - app_type, - app_type_other, - appliance_id, - ): - create_volume_dict = {} - if name is not None: - create_volume_dict["name"] = name - if size is not None: - create_volume_dict["size"] = size - if description is not None: - create_volume_dict["description"] = description - if volume_group_id is not None: - create_volume_dict["volume_group_id"] = volume_group_id - if protection_policy_id is not None: - create_volume_dict["protection_policy_id"] = protection_policy_id - if performance_policy_id is not None: - create_volume_dict["performance_policy_id"] = performance_policy_id - if app_type is not None: - create_volume_dict["app_type"] = app_type - if app_type_other is not None: - create_volume_dict["app_type_other"] = app_type_other - if appliance_id is not None: - create_volume_dict["appliance_id"] = appliance_id - - return create_volume_dict - - def delete_volume(self, volume_id): - """Delete a volume. - - :param volume_id: The Volume ID - :type volume_id: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Deleting volume: '%s'", volume_id) - return self.client.request( - constants.DELETE, - constants.DELETE_VOLUME_URL.format(self.server_ip, volume_id), - payload=None, - ) - - def modify_volume( - self, - volume_id, - name=None, - description=None, - size=None, - protection_policy_id=None, - performance_policy_id=None, - app_type=None, - app_type_other=None, - ): - """Modify a volume. - - :param volume_id: The volume ID - :type volume_id: str - :param name: The name of the volume - :type name: str - :param description: The description of the volume - :type description: str - :param size: The size of the volume - :type size: str - :param protection_policy_id: The protection policy ID - :type protection_policy_id: str - :param performance_policy_id: The performance policy ID - :type performance_policy_id: str - :param app_type: The application type - :type app_type: str - :param app_type_other: Describes application type when - app_type is set to other - :return: None if success else raise exception - :rtype: None - """ - if app_type is not None and not helpers.is_malka_or_higher(): - raise Exception( - "'app_type' parameter is supported only from " - "Powerstore version 2.1.0.0 onwards", - ) - - LOG.info( "Modifying volume: '%s'", volume_id) - payload = self._prepare_modify_volume_payload( - name, - description, - size, - protection_policy_id, - performance_policy_id, - app_type, - app_type_other, - ) - return self.client.request( - constants.PATCH, - constants.MODIFY_VOLUME_URL.format(self.server_ip, volume_id), - payload, - ) - - def _prepare_modify_volume_payload( - self, - name=None, - description=None, - size=None, - protection_policy_id=None, - performance_policy_id=None, - app_type=None, - app_type_other=None, - ): - modify_volume_dict = {} - if name is not None: - modify_volume_dict["name"] = name - if description is not None: - modify_volume_dict["description"] = description - if size is not None: - modify_volume_dict["size"] = size - if protection_policy_id is not None: - modify_volume_dict["protection_policy_id"] = protection_policy_id - if performance_policy_id is not None: - modify_volume_dict["performance_policy_id"] = performance_policy_id - if app_type is not None: - modify_volume_dict["app_type"] = app_type - if app_type_other is not None: - modify_volume_dict["app_type_other"] = app_type_other - - return modify_volume_dict - - def clone_volume( - self, - volume_id, - name=None, - description=None, - host_id=None, - host_group_id=None, - logical_unit_number=None, - protection_policy_id=None, - performance_policy_id=None, - ): - """Clone a volume. - - :param volume_id: The volume ID - :type volume_id: str - :param name: Name of the clone - :type name: str - :param description: Description of the clone - :type description: str - :param host_id: Unique identifier of the host to be attached to the clone. - :type host_id: str - :param host_group_id: Unique identifier of the host group to be attached to the clone. - :type host_group_id: str - :param logical_unit_number: Optional logical unit number when creating a mapped volume. - :type logical_unit_number: int - :param protection_policy_id: The protection policy ID - :type protection_policy_id: str - :param performance_policy_id: The performance policy ID - :type performance_policy_id: str - :return: 'id' Unique identifier of the new clone volume if success else raise exception - :rtype: dict - """ - LOG.info( "Cloning the volume: '%s'", volume_id) - payload = self._prepare_clone_volume_payload( - name, - description, - host_id, - host_group_id, - logical_unit_number, - protection_policy_id, - performance_policy_id, - ) - return self.client.request( - constants.POST, - constants.CLONE_VOLUME_URL.format(self.server_ip, volume_id), - payload, - ) - - def _prepare_clone_volume_payload( - self, - name=None, - description=None, - host_id=None, - host_group_id=None, - logical_unit_number=None, - protection_policy_id=None, - performance_policy_id=None, - ): - clone_volume_dict = {} - if name is not None: - clone_volume_dict["name"] = name - if description is not None: - clone_volume_dict["description"] = description - if host_id is not None: - clone_volume_dict["host_id"] = host_id - if host_group_id is not None: - clone_volume_dict["host_group_id"] = host_group_id - if logical_unit_number is not None: - clone_volume_dict["logical_unit_number"] = logical_unit_number - if protection_policy_id is not None: - clone_volume_dict["protection_policy_id"] = protection_policy_id - if performance_policy_id is not None: - clone_volume_dict["performance_policy_id"] = performance_policy_id - - return clone_volume_dict - - def refresh_volume( - self, - volume_id, - volume_id_to_refresh_from=None, - create_backup_snap=None, - backup_snap_name=None, - backup_snap_description=None, - backup_snap_expiration_timestamp=None, - backup_snap_performance_policy_id=None, - ): - """Refresh a volume. - - :param volume_id: The volume ID - :type volume_id: str - :param volume_id_to_refresh_from: Unique identifier of the source volume that will be used for the refresh operation - :type volume_id_to_refresh_from: str - :param create_backup_snap: Indicates whether a backup snapshot of the target volume will be created before it is refreshed from the source volume - :type create_backup_snap: bool - :param backup_snap_name: Name of the backup snapshot to be created. The default name of the volume snapshot is the date and time when the snapshot is taken - :type backup_snap_name: str - :param backup_snap_description: Description of the backup snapshot. - :type backup_snap_description: str - :param backup_snap_performance_policy_id: Unique identifier of the performance policy assigned to the snapshot. - :type backup_snap_performance_policy_id: str - :param backup_snap_expiration_timestamp: Time at which the backup snapshot will expire. - :type backup_snap_expiration_timestamp: str - :return: 'backup_snapshot_id' Unique identifier of the backup snapshot of the target volume, if one is created prior to the refresh operation. - :rtype: dict - """ - LOG.info( "Refreshing the volume: '%s'", volume_id) - payload = self._prepare_refresh_volume_payload( - volume_id_to_refresh_from, - create_backup_snap, - backup_snap_name, - backup_snap_description, - backup_snap_expiration_timestamp, - backup_snap_performance_policy_id, - ) - return self.client.request( - constants.POST, - constants.REFRESH_VOLUME_URL.format(self.server_ip, volume_id), - payload, - ) - - def _prepare_refresh_volume_payload( - self, - volume_id_to_refresh_from=None, - create_backup_snap=None, - backup_snap_name=None, - backup_snap_description=None, - backup_snap_expiration_timestamp=None, - backup_snap_performance_policy_id=None, - ): - refresh_volume_dict = {} - if volume_id_to_refresh_from is not None: - refresh_volume_dict["from_object_id"] = volume_id_to_refresh_from - if create_backup_snap is not None: - refresh_volume_dict["create_backup_snap"] = create_backup_snap - - refresh_volume_dict["backup_snap_profile"] = {} - if backup_snap_name is not None: - refresh_volume_dict["backup_snap_profile"]["name"] = backup_snap_name - if backup_snap_description is not None: - refresh_volume_dict["backup_snap_profile"][ - "description" - ] = backup_snap_description - if backup_snap_expiration_timestamp is not None: - refresh_volume_dict["backup_snap_profile"][ - "expiration_timestamp" - ] = backup_snap_expiration_timestamp - if backup_snap_performance_policy_id is not None: - refresh_volume_dict["backup_snap_profile"][ - "performance_policy_id" - ] = backup_snap_performance_policy_id - - return refresh_volume_dict - - def restore_volume( - self, - volume_id, - snap_id_to_restore_from=None, - create_backup_snap=None, - backup_snap_name=None, - backup_snap_description=None, - backup_snap_expiration_timestamp=None, - backup_snap_performance_policy_id=None, - ): - """Restore a volume. - - :param volume_id: The volume ID - :type volume_id: str - :param snap_id_to_restore_from: Unique identifier of the source snapshot that will be used for the restore operation. - :type snap_id_to_restore_from: str - :param create_backup_snap: Indicates whether a backup snapshot of the target volume will be created before it is restored from the snapshot. - :type create_backup_snap: bool - :param backup_snap_name: Name of the backup snapshot to be created. The default name of the volume snapshot is the date and time when the snapshot is taken - :type backup_snap_name: str - :param backup_snap_description: Description of the backup snapshot. - :type backup_snap_description: str - :param backup_snap_performance_policy_id: Unique identifier of the performance policy assigned to the snapshot. - :type backup_snap_performance_policy_id: str - :param backup_snap_expiration_timestamp: Time at which the backup snapshot will expire. - :type backup_snap_expiration_timestamp: str - :return: 'backup_snapshot_id' Unique identifier of the backup snapshot of the target volume, if one is created prior to the restore operation. - :rtype: dict - """ - LOG.info( "Restoring the volume: '%s'", volume_id) - payload = self._prepare_restore_volume_payload( - snap_id_to_restore_from, - create_backup_snap, - backup_snap_name, - backup_snap_description, - backup_snap_expiration_timestamp, - backup_snap_performance_policy_id, - ) - return self.client.request( - constants.POST, - constants.RESTORE_VOLUME_URL.format(self.server_ip, volume_id), - payload, - ) - - def _prepare_restore_volume_payload( - self, - snap_id_to_restore_from=None, - create_backup_snap=None, - backup_snap_name=None, - backup_snap_description=None, - backup_snap_expiration_timestamp=None, - backup_snap_performance_policy_id=None, - ): - refresh_volume_dict = {} - if snap_id_to_restore_from is not None: - refresh_volume_dict["from_snap_id"] = snap_id_to_restore_from - if create_backup_snap is not None: - refresh_volume_dict["create_backup_snap"] = create_backup_snap - - refresh_volume_dict["backup_snap_profile"] = {} - if backup_snap_name is not None: - refresh_volume_dict["backup_snap_profile"]["name"] = backup_snap_name - if backup_snap_description is not None: - refresh_volume_dict["backup_snap_profile"][ - "description" - ] = backup_snap_description - if backup_snap_expiration_timestamp is not None: - refresh_volume_dict["backup_snap_profile"][ - "expiration_timestamp" - ] = backup_snap_expiration_timestamp - if backup_snap_performance_policy_id is not None: - refresh_volume_dict["backup_snap_profile"][ - "performance_policy_id" - ] = backup_snap_performance_policy_id - - return refresh_volume_dict - - def clone_filesystem(self, filesystem_id, advance_parameters): - """Clone a filesystem. - - :param filesystem_id: The filesystem ID - :type filesystem_id: str - :param advance_parameters: Advance attributes - :type advance_parameters: str - :return: Unique identifier of the new instance created if success else raise exception - :rtype: dict - """ - LOG.info( "Cloning the filesystem: '%s'", filesystem_id) - payload = {} - - if advance_parameters: - for key, value in advance_parameters.items(): - if ( - key in constants.FILESYSTEM_PRIME - and not helpers.is_foot_hill_prime_or_higher() - ): - raise Exception( - key + " is supported for PowerStore version 3.0.0.0 and above.", - ) - payload[key] = value - return self.client.request( - constants.POST, - constants.CLONE_FILESYSTEM_URL.format(self.server_ip, filesystem_id), - payload, - ) - - def restore_filesystem(self, snapshot_id, backup_snap_name=None): - """Restore a filesystem. - - :param snapshot_id: Unique identifier of the file system snapshot. - :type snapshot_id: str - :param backup_snap_name: Name of the backup snap to be created before the restore operation occurs. If no name is specified, no backup copy will be made. - :type backup_snap_name: str - :return: Unique identifier of the backup snapshot set or None if backup_snap_name is None - if success else raise exception - :rtype: dict - """ - LOG.info( "Restoring the filesystem from snapshot: '%s'", snapshot_id) - payload = {} - if backup_snap_name is not None: - payload["copy_name"] = backup_snap_name - return self.client.request( - constants.POST, - constants.RESTORE_FILESYSTEM_URL.format(self.server_ip, snapshot_id), - payload, - ) - - def refresh_filesystem(self, snapshot_id): - """Refresh a filesystem. - - :param snapshot_id: Unique identifier of the file system snapshot. - :type snapshot_id: str - :return: None if success else raise exception. - :rtype: None - """ - LOG.info( "Refreshing the filesystem from snapshot: '%s'", snapshot_id) - return self.client.request( - constants.POST, - constants.REFRESH_FILESYSTEM_URL.format(self.server_ip, snapshot_id), - ) - - def add_protection_policy_for_volume(self, volume_id, protection_policy_id): - """Add protection policy for volume. - - :param volume_id: The volume ID - :type volume_id: str - :param protection_policy_id: The protection policy ID - :type protection_policy_id: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( - f"Adding protection policy: '{protection_policy_id}' for volume: '{volume_id}'", - ) - payload = self._prepare_modify_volume_payload( - protection_policy_id=protection_policy_id, - ) - return self.client.request( - constants.PATCH, - constants.MODIFY_VOLUME_URL.format(self.server_ip, volume_id), - payload, - ) - - def remove_protection_policy_for_volume(self, volume_id): - """Remove protection policy for volume. - - :param volume_id: The volume ID - :type volume_id: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Removing protection policy for volume: '%s'", volume_id) - payload = {"protection_policy_id": ""} - return self.client.request( - constants.PATCH, - constants.MODIFY_VOLUME_URL.format(self.server_ip, volume_id), - payload, - ) - - def map_volume_to_host(self, volume_id, host_id=None, logical_unit_number=None): - """Map a volume to a Host. - - :param volume_id: The volume ID - :type volume_id: str - :param host_id: (optional) The host ID - :type host_id: str - :param logical_unit_number: (optional) The logical unit number - :type logical_unit_number: str - """ - LOG.info( "Mapping volume: '%s' to host", volume_id) - payload = self._prepare_map_vol_to_host_payload(host_id, logical_unit_number) - self.client.request( - constants.POST, - constants.MAP_VOLUME_TO_HOST_URL.format(self.server_ip, volume_id), - payload, - ) - - def _prepare_map_vol_to_host_payload(self, host_id, logical_unit_number): - map_volume_to_host_dict = {} - if host_id is not None: - map_volume_to_host_dict["host_id"] = host_id - if logical_unit_number is not None: - map_volume_to_host_dict["logical_unit_number"] = logical_unit_number - - return map_volume_to_host_dict - - def map_volume_to_host_group( - self, volume_id, host_group_id=None, logical_unit_number=None, - ): - """Map a volume to a Host. - - :param volume_id: The volume ID - :type volume_id: str - :param host_group_id: (optional) The host group ID - :type host_group_id: str - :param logical_unit_number: (optional) The logical unit number - :type logical_unit_number: str - """ - LOG.info( "Mapping volume: '%s' to host group", volume_id) - payload = self._prepare_map_vol_to_host_grp_payload( - host_group_id, logical_unit_number, - ) - self.client.request( - constants.POST, - constants.MAP_VOLUME_TO_HOST_URL.format(self.server_ip, volume_id), - payload, - ) - - def _prepare_map_vol_to_host_grp_payload(self, host_grp_id, logical_unit_number): - map_volume_to_host_dict = {} - if host_grp_id is not None: - map_volume_to_host_dict["host_group_id"] = host_grp_id - if logical_unit_number is not None: - map_volume_to_host_dict["logical_unit_number"] = logical_unit_number - - return map_volume_to_host_dict - - def unmap_volume_from_host(self, volume_id, host_id): - """Unmap a Volume from a Host. - - :param volume_id: The volume ID - :type volume_id: str - :param host_id: The host ID - :type host_id: str - """ - LOG.info( "Unmapping volume: '%s' from host: '%s'", volume_id, host_id) - payload = self._prepare_unmap_vol_from_host_payload(host_id) - self.client.request( - constants.POST, - constants.UNMAP_VOLUME_FROM_HOST_URL.format(self.server_ip, volume_id), - payload, - ) - - def _prepare_unmap_vol_from_host_payload(self, host_id): - unmap_vol_from_host_dict = {} - if host_id is not None: - unmap_vol_from_host_dict["host_id"] = host_id - - return unmap_vol_from_host_dict - - def unmap_volume_from_host_group(self, volume_id, host_group_id): - """Unmap a Volume from a Host. - - :param volume_id: The volume ID - :type volume_id: str - :param host_group_id: The host group ID - :type host_group_id: str - """ - LOG.info( - f"Unmapping volume: '{volume_id}' from host group: '{host_group_id}'", - ) - payload = self._prepare_unmap_vol_from_host_grp_payload(host_group_id) - self.client.request( - constants.POST, - constants.UNMAP_VOLUME_FROM_HOST_URL.format(self.server_ip, volume_id), - payload, - ) - - def _prepare_unmap_vol_from_host_grp_payload(self, host_group_id): - unmap_vol_from_host_dict = {} - if host_group_id is not None: - unmap_vol_from_host_dict["host_group_id"] = host_group_id - - return unmap_vol_from_host_dict - - def get_volumes(self, filter_dict=None, all_pages=False): - """Get a list of volumes. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :return: Volume details - :rtype: list of dict - """ - LOG.info( - f"Getting volumes with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ID_AND_NAME, filter_dict, - ) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_VOLUME_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def get_volume_details(self, volume_id): - """Get details of a volume. - - :param volume_id: The volume ID - :type volume_id: str - :return: Volume details - :rtype: dict - """ - LOG.info( "Getting volume details by ID: '%s'", volume_id) - querystring = constants.SELECT_ALL_VOLUME - if helpers.is_victory_or_higher(): - querystring = constants.VICTORY_VOLUME_DETAILS_QUERY - elif helpers.is_foot_hill_prime_or_higher(): - querystring = constants.FHP_VOLUME_DETAILS_QUERY - elif helpers.is_foot_hill_or_higher(): - querystring = constants.FHC_VOLUME_DETAILS_QUERY - - resp = self.client.request( - constants.GET, - constants.GET_VOLUME_DETAILS_URL.format(self.server_ip, volume_id), - payload=None, - querystring=querystring, - ) - - hlu_details = self.get_host_volume_mapping(volume_id=volume_id) - - resp["hlu_details"] = hlu_details - - return resp - - def get_volume_by_name(self, volume_name): - """Get details of a volume by name. - - :param volume_name: The volume name - :type volume_name: str - :return: Volume details - :rtype: dict - """ - LOG.info( "Getting volume details by name: '%s'", volume_name) - querystring = constants.SELECT_ALL_VOLUME - if helpers.is_victory_or_higher(): - querystring = constants.VICTORY_VOLUME_DETAILS_QUERY - elif helpers.is_foot_hill_prime_or_higher(): - querystring = constants.FHP_VOLUME_DETAILS_QUERY - elif helpers.is_foot_hill_or_higher(): - querystring = constants.FHC_VOLUME_DETAILS_QUERY - - resp = self.client.request( - constants.GET, - constants.GET_VOLUME_BY_NAME_URL.format(self.server_ip), - payload=None, - querystring=helpers.prepare_querystring( - querystring, name=constants.EQUALS + volume_name, - ), - ) - - if resp: - LOG.info( "Getting host volume mapping from vol ID: '%s'", resp[0]['id']) - hlu_details = self.get_host_volume_mapping(volume_id=resp[0]["id"]) - resp[0]["hlu_details"] = hlu_details - - return resp - - def configure_metro_volume( - self, volume_id, remote_system_id, remote_appliance_id=None, - ): - """Configure the metro volume - :param volume_id: ID of the volume - :type volume_id: str - :param remote_system_id: ID of the remote system - :type remote_system_id: str - :param remote_appliance_id: ID of remote appliance to which volume will - be assigned - :type remote_appliance_id: str - :return: ID of metro session - :rtype: str - """ - LOG.info( - f"Configuring the metro volume {volume_id} to remote system {remote_system_id}", - ) - - if helpers.is_foot_hill_prime_or_higher(): - metro_url = constants.CONFIGURE_METRO_VOLUME - payload = {} - payload["remote_system_id"] = remote_system_id - if remote_appliance_id is not None: - payload["remote_appliance_id"] = remote_appliance_id - - return self.client.request( - constants.POST, - metro_url.format(self.server_ip, volume_id), - payload=payload, - ) - raise Exception("Not supported for PowerStore version less than 3.0.0.0") - - def end_volume_metro_config(self, volume_id, delete_remote_volume=None): - """End a metro configuration from a volume and keep both copies.The local - copy will retain its SCSI Identity while the remote volume will get a - new SCSI Identity - :param volume_id: ID of the volume - :type volume_id: str - :param delete_remote_volume: Whether to delete the remote volume during - the removal - :type delete_remote_volume: bool - :return: None if success else raise exception - :rtype: None - """ - LOG.info("End a metro configuration from a volume %s", volume_id) - if helpers.is_foot_hill_prime_or_higher(): - end_metro_url = constants.END_METRO_VOLUME - payload = {} - if delete_remote_volume is not None: - payload["delete_remote_volume"] = delete_remote_volume - - return self.client.request( - constants.POST, - end_metro_url.format(self.server_ip, volume_id), - payload=payload, - ) - raise Exception("Not supported for PowerStore version less than 3.0.0.0") - - def get_hosts(self, filter_dict=None, all_pages=False): - """Get a list of all the registered hosts. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :return: Hosts - :rtype: list of dict - """ - LOG.info( - f"Getting hosts with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ID_AND_NAME, filter_dict, - ) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_HOST_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def create_host( - self, name, os_type, initiators, description=None, host_connectivity=None, - ): - """Register a host on the array. - - :param name: The name of the host - :type name: str - :param os_type: The OS type of the host - :type os_type: str - :param initiators: Host initiators - :type initiators: list of dict - :param description: (optional) The description for the host - :type description: str - :param host_connectivity: (optional) Connectivity type for hosts - :type host_connectivity: str - :return: Host ID if success else raise exception - :rtype: dict - """ - LOG.info( - f"Creating host with name: '{name}' os_type: '{os_type}' initiators: '{initiators}'", - ) - payload = self._prepare_create_host_payload( - name, description, os_type, initiators, host_connectivity, - ) - return self.client.request( - constants.POST, constants.CREATE_HOST_URL.format(self.server_ip), payload, - ) - - def _prepare_create_host_payload( - self, name, description, os_type, initiators, host_connectivity, - ): - create_host_dict = {} - if name is not None: - create_host_dict["name"] = name - if description is not None: - create_host_dict["description"] = description - if os_type is not None: - create_host_dict["os_type"] = os_type - if initiators is not None: - create_host_dict["initiators"] = initiators - if host_connectivity is not None: - create_host_dict["host_connectivity"] = host_connectivity - - return create_host_dict - - def get_host_details(self, host_id): - """Get details of a particular host. - - :param host_id: The host ID - :type host_id: str - :return: Host details - :rtype: dict - """ - LOG.info( "Getting host details by ID: '%s'", host_id) - querystring = constants.SELECT_ALL_HOST - if helpers.is_foot_hill_prime_or_higher(): - querystring = constants.FHP_HOST_DETAILS_QUERY - elif helpers.is_foot_hill_or_higher(): - querystring = constants.FHC_HOST_DETAILS_QUERY - return self.client.request( - constants.GET, - constants.GET_HOST_DETAILS_URL.format(self.server_ip, host_id), - payload=None, - querystring=querystring, - ) - - def modify_host( - self, - host_id, - name=None, - description=None, - remove_initiators=None, - add_initiators=None, - modify_initiators=None, - host_connectivity=None, - ): - """Modify a given host - Only one of add, remove - or update in the same request. - - :param host_id: The host ID - :type host_id: str - :param name: (optional) The host name - :type name: str - :param description: (optional) The description for the host - :type description: str - :param remove_initiators: (optional) Initiators to be removed - :type remove_initiators: list - :param add_initiators: (optional) Initiators to be added - :type add_initiators: list - :param modify_initiators: (optional) Initiators to be modified - :type modify_initiators: list - :param host_connectivity: (optional)Connectivity types for hosts - :type host_connectivity: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Modifying host: '%s'", host_id) - payload = self._prepare_modify_host_payload( - name, - description, - remove_initiators, - add_initiators, - modify_initiators, - host_connectivity, - ) - return self.client.request( - constants.PATCH, - constants.MODIFY_HOST_URL.format(self.server_ip, host_id), - payload, - ) - - def _prepare_modify_host_payload( - self, - name=None, - description=None, - remove_initiators=None, - add_initiators=None, - modify_initiators=None, - host_connectivity=None, - ): - modify_host_dict = {} - if name is not None: - modify_host_dict["name"] = name - if description is not None: - modify_host_dict["description"] = description - if remove_initiators is not None: - modify_host_dict["remove_initiators"] = remove_initiators - elif add_initiators is not None: - modify_host_dict["add_initiators"] = add_initiators - elif modify_initiators is not None: - modify_host_dict["modify_initiators"] = modify_initiators - elif host_connectivity is not None: - modify_host_dict["host_connectivity"] = host_connectivity - - return modify_host_dict - - def add_initiators_to_host(self, host_id, add_initiators=None): - """Add initiators to host. - - :param host_id: The host ID. - :type host_id: str - :param add_initiators: (optional) Initiators to be added. - :type add_initiators: list - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Adding initiators to host: '%s'", host_id) - payload = self._prepare_modify_host_payload(add_initiators=add_initiators) - return self.client.request( - constants.PATCH, - constants.MODIFY_HOST_URL.format(self.server_ip, host_id), - payload, - ) - - def remove_initiators_from_host(self, host_id, remove_initiators=None): - """Remove initiators from Host. - - :param host_id: The host ID - :type host_id: str - :param remove_initiators: (optional) Initiators to be removed - :type remove_initiators: list - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Removing initiators to host: '%s'", host_id) - payload = self._prepare_modify_host_payload(remove_initiators=remove_initiators) - return self.client.request( - constants.PATCH, - constants.MODIFY_HOST_URL.format(self.server_ip, host_id), - payload, - ) - - def delete_host(self, host_id, force=None): - """Delete a host. - - :param host_id: The host ID. - :type host_id: str - :param force: (optional) The force_internal flag. - :type force: bool - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Deleting host: '%s'", host_id) - if force: - payload = {"force_internal": force} - else: - payload = None - return self.client.request( - constants.DELETE, - constants.DELETE_HOST_URL.format(self.server_ip, host_id), - payload, - ) - - def get_host_by_name(self, host_name): - """Get details of a Host with its name. - - :param host_name: The Host name. - :type host_name: str - :return: Host details - :rtype: dict - """ - LOG.info( "Getting host details by name: '%s'", host_name) - querystring = constants.SELECT_ALL_HOST - if helpers.is_foot_hill_prime_or_higher(): - querystring = constants.FHP_HOST_DETAILS_QUERY - elif helpers.is_foot_hill_or_higher(): - querystring = constants.FHC_HOST_DETAILS_QUERY - return self.client.request( - constants.GET, - constants.GET_HOST_BY_NAME_URL.format(self.server_ip), - payload=None, - querystring=helpers.prepare_querystring( - querystring, name=constants.EQUALS + host_name, - ), - ) - - def get_host_group_list(self, filter_dict=None, all_pages=False): - """Get a list of all host groups. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :return: Hosts - :rtype: list of dict - """ - LOG.info( - f"Getting hostgroup with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ID_AND_NAME, filter_dict, - ) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_HOST_GROUP_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def create_host_group(self, name, host_ids, description=None): - """Create a Host Group. - - :param name: The name of the host group - :type name: str - :param host_ids: Host IDs - :type host_ids: list - :param description: (optional) The description for the host group - :type description: str - :return: Host group ID if success else raise exception - :rtype: dict - """ - LOG.info( "Creating hostgroup: '%s' with host_ids: '%s'", name, host_ids) - payload = self._prepare_create_host_group_payload(name, host_ids, description) - return self.client.request( - constants.POST, - constants.CREATE_HOST_GROUP_URL.format(self.server_ip), - payload, - ) - - def _prepare_create_host_group_payload(self, name, host_ids, description): - create_host_group_dict = {} - if name is not None: - create_host_group_dict["name"] = name - if host_ids is not None: - create_host_group_dict["host_ids"] = host_ids - if description is not None: - create_host_group_dict["description"] = description - - return create_host_group_dict - - def get_host_group_details(self, host_group_id): - """Get details of a particular host group. - - :param host_group_id: The Host Group ID - :type host_group_id: str - :return: Host group details - :rtype: dict - """ - LOG.info( "Getting hostgroup details by ID: '%s'", host_group_id) - querystring = constants.SELECT_ALL_HOST_GROUP - if helpers.is_foot_hill_prime_or_higher(): - querystring = constants.FHP_HOST_GROUP_QUERY - - return self.client.request( - constants.GET, - constants.GET_HOST_GROUP_DETAILS_URL.format(self.server_ip, host_group_id), - payload=None, - querystring=querystring, - ) - - def get_host_group_by_name(self, host_group_name): - """Get details of a Host Group with its name. - - :param host_group_name: The Host Group name - :type host_group_name: str - :return: Host group details - :rtype: dict - """ - LOG.info( "Getting hostgroup details by name: '%s'", host_group_name) - querystring = constants.SELECT_ALL_HOST_GROUP - if helpers.is_foot_hill_prime_or_higher(): - querystring = constants.FHP_HOST_GROUP_QUERY - - return self.client.request( - constants.GET, - constants.GET_HOST_GROUP_BY_NAME_URL.format(self.server_ip), - payload=None, - querystring=helpers.prepare_querystring( - querystring, name=constants.EQUALS + host_group_name, - ), - ) - - def get_hosts_from_host_group(self, host_group_name): - """Get list of hosts which belong to Host Group. - - :param host_group_name: The Host Group name - :type host_group_name: str - :return: Hosts which are part of Host Group - :rtype: list - """ - LOG.info( "Getting hosts from host_group: '%s'", host_group_name) - return self.client.request( - constants.GET, - constants.GET_HOSTS_BY_HOST_GROUP.format(self.server_ip, host_group_name), - payload=None, - querystring=helpers.prepare_querystring( - name=constants.EQUALS + host_group_name, select="hosts(name,id)", - ), - ) - - def modify_host_group( - self, - host_group_id, - name=None, - remove_host_ids=None, - add_host_ids=None, - description=None, - host_connectivity=None, - ): - """Modify a Host group. - - :param host_group_id: The ID of the host group to be modified - :type host_group_id: str - :param name: (optional) The modified name of the host group - :type name: str - :param remove_host_ids: (optional) The hosts to be removed from - host group - :type remove_host_ids: list - :param add_host_ids: (optional) The hosts to be added to the host group - :type add_host_ids: list - :param description: (optional) The modified description for the - host group - :type description: str - :param host_connectivity: (Optional)Connectivity for host group - :type host_connectivity: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Modifying hostgroup: '%s'", host_group_id) - payload = self._prepare_modify_host_group_payload( - name, remove_host_ids, add_host_ids, description, host_connectivity, - ) - return self.client.request( - constants.PATCH, - constants.MODIFY_HOST_GROUP_URL.format(self.server_ip, host_group_id), - payload, - ) - - def _prepare_modify_host_group_payload( - self, - name=None, - remove_host_ids=None, - add_host_ids=None, - description=None, - host_connectivity=None, - ): - modify_host_group_dict = {} - if name is not None: - modify_host_group_dict["name"] = name - if description is not None: - modify_host_group_dict["description"] = description - if host_connectivity is not None: - modify_host_group_dict["host_connectivity"] = host_connectivity - - if remove_host_ids is not None: - modify_host_group_dict["remove_host_ids"] = remove_host_ids - elif add_host_ids is not None: - modify_host_group_dict["add_host_ids"] = add_host_ids - - return modify_host_group_dict - - def add_hosts_to_host_group(self, host_group_id, add_host_ids=None): - """Add Hosts to Host Group. - - :param host_group_id: The ID of the host group to be modified. - :type host_group_id: str - :param add_host_ids: (optional) The hosts to be added to the host group - :type add_host_ids: list - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Adding hosts to host_group: '%s'", host_group_id) - payload = self._prepare_modify_host_group_payload(add_host_ids=add_host_ids) - return self.client.request( - constants.PATCH, - constants.MODIFY_HOST_GROUP_URL.format(self.server_ip, host_group_id), - payload, - ) - - def remove_hosts_from_host_group(self, host_group_id, remove_host_ids=None): - """Remove Hosts from Host Group. - - :param host_group_id: The ID of the host group to be modified - :type host_group_id: str - :param remove_host_ids: (optional) Hosts to be removed from host group - :type remove_host_ids: list - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Removing hosts from host_group: '%s'", host_group_id) - payload = self._prepare_modify_host_group_payload( - remove_host_ids=remove_host_ids, - ) - return self.client.request( - constants.PATCH, - constants.MODIFY_HOST_GROUP_URL.format(self.server_ip, host_group_id), - payload, - ) - - def delete_host_group(self, host_group_id): - """Delete a host group. - - :param host_group_id: The ID of the host group - :type host_group_id: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Deleting hostgroup: '%s'", host_group_id) - return self.client.request( - constants.DELETE, - constants.DELETE_HOST_GROUP_URL.format(self.server_ip, host_group_id), - payload=None, - ) - - def get_volumes_from_volume_group(self, vol_group_name): - """Get a list of volumes which belong to Volume Group. - - :param vol_group_name: The Volume group name - :type vol_group_name: str - :return: Volumes which are part of Volume Group - :rtype: list - """ - LOG.info( "Getting volumes from volumegroup: %s", vol_group_name) - return self.client.request( - constants.GET, - constants.GET_VOLUMES_FROM_VOLUME_GROUP.format( - self.server_ip, vol_group_name, - ), - payload=None, - querystring=helpers.prepare_querystring( - name=constants.EQUALS + vol_group_name, select="volumes(name)", - ), - ) - - def get_volume_group_list(self, filter_dict=None, all_pages=False): - """Get a list of all the volume groups. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :return: Volume Groups - :rtype: list of dict - """ - LOG.info( - f"Getting volumegroups with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ID_AND_NAME, filter_dict, - ) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_VOLUME_GROUP_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def create_volume_group( - self, - name, - description=None, - volume_ids=None, - is_write_order_consistent=None, - protection_policy_id=None, - ): - """Create a volume group. - - :param name: The name of the volume group. - :type name: str - :param description: (optional) The description of the VG. - :type description: str - :param volume_ids: (optional) The volume IDs to be added to the VG - :type volume_ids: list - :param is_write_order_consistent: (optional) Indicate whether snapshot - sets of the volume group will be - write-order consistent. - :type is_write_order_consistent: vool - :param protection_policy_id: (optional) Unique identifier of a - protection policy to assign - to the volume group. - :type protection_policy_id: str - :return: Volume ID if success else raise exception - :rtype: dict - """ - LOG.info( "Creating volumegroup: '%s'", name) - payload = self._prepare_create_vg_payload( - name, - description, - volume_ids, - is_write_order_consistent, - protection_policy_id, - ) - return self.client.request( - constants.POST, - constants.CREATE_VOLUME_GROUP_URL.format(self.server_ip), - payload=payload, - ) - - def clone_volume_group( - self, volume_group_id, name, description=None, protection_policy_id=None, - ): - """Clone a volume group. - - :param volume_group_id: ID of the volume group to clone - :type volume_group_id: str - :param name: Unique name for the clone volume group. - :type name: str - :param description: (optional) Description for the clone volume group. - :type description: str - :param protection_policy_id: (optional) Unique identifier of the protection - policy to assign to the clone volume group - :type protection_policy_id: str - :return: Unique identifier of the new instance created if success else raise exception - :rtype: dict - """ - LOG.info( "Cloning volumegroup: '%s'", volume_group_id) - payload = self._prepare_clone_vg_payload( - name, description, protection_policy_id, - ) - return self.client.request( - constants.POST, - constants.CLONE_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), - payload=payload, - ) - - def refresh_volume_group( - self, - volume_group_id, - src_vol_group, - create_backup_snap=None, - backup_snap_profile=None, - ): - """Refresh a volume group. - - :param volume_group_id: ID of the volume group to refresh - :type volume_group_id: str - :param src_vol_group: Unique identifier of the volume group to refresh from. - :type src_vol_group: str - :param create_backup_snap: (optional) specifies whether a backup snapshot set of the - target volume group needs to be created before refreshing it. - :type create_backup_snap: bool - :param backup_snap_profile: (optional) Backup profile of the snapshot set to be created. - :type backup_snap_profile: dict - :return: Unique identifier of the backup snapshot set or None if create_backup_snap is None - if success else raise exception - :rtype: dict - """ - LOG.info( "Refreshing volumegroup: '%s'", volume_group_id) - payload = self._prepare_vg_payload( - "refresh", src_vol_group, create_backup_snap, backup_snap_profile, - ) - return self.client.request( - constants.POST, - constants.REFRESH_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), - payload=payload, - ) - - def restore_volume_group( - self, - volume_group_id, - src_snap_id, - create_backup_snap=None, - backup_snap_profile=None, - ): - """Restore a volume group. - - :param volume_group_id: ID of the volume group to restore - :type volume_group_id: str - :param src_snap_id: Unique identifier of the snapshot set to restore from. - :type src_snap_id: str - :param create_backup_snap: (optional) specifies whether a backup snapshot set of the - target volume group needs to be created before restore. - :type create_backup_snap: bool - :param backup_snap_profile: (optional) Backup profile of the snapshot set to be created. - :type backup_snap_profile: dict - :return: Unique identifier of the backup snapshot set or None if create_backup_snap is None - if success else raise exception - :rtype: dict - """ - LOG.info( "Restoring volumegroup: '%s'", volume_group_id) - payload = self._prepare_vg_payload( - "restore", src_snap_id, create_backup_snap, backup_snap_profile, - ) - return self.client.request( - constants.POST, - constants.RESTORE_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), - payload=payload, - ) - - def _prepare_clone_vg_payload(self, name, description, protection_policy_id): - vol_group_clone = {} - if name is not None: - vol_group_clone["name"] = name - if description is not None: - vol_group_clone["description"] = description - if protection_policy_id is not None: - vol_group_clone["protection_policy_id"] = protection_policy_id - return vol_group_clone - - def _prepare_vg_payload( - self, action, src_vol_group, create_backup_snap, backup_snap_profile, - ): - vg_payload = {} - if action == "refresh": - vg_payload["from_object_id"] = src_vol_group - else: - vg_payload["from_snap_id"] = src_vol_group - if create_backup_snap is not None: - vg_payload["create_backup_snap"] = create_backup_snap - if backup_snap_profile: - vg_payload["backup_snap_profile"] = backup_snap_profile - - return vg_payload - - def _prepare_create_vg_payload( - self, - name, - description, - volume_ids, - is_write_order_consistent, - protection_policy_id, - ): - create_volume_group_dict = {} - if name is not None: - create_volume_group_dict["name"] = name - if description is not None: - create_volume_group_dict["description"] = description - if volume_ids is not None: - create_volume_group_dict["volume_ids"] = volume_ids - if is_write_order_consistent is not None: - create_volume_group_dict["is_write_order_consistent"] = ( - is_write_order_consistent - ) - if protection_policy_id is not None: - create_volume_group_dict["protection_policy_id"] = protection_policy_id - - return create_volume_group_dict - - def get_volume_group_details(self, volume_group_id): - """Get details of a volume group. - - :param volume_group_id: The volume group ID - :type volume_group_id: str - :return: Details of the volume group - :rtype: dict - """ - LOG.info( "Getting volumegroup details by ID: '%s'", volume_group_id) - return self.client.request( - constants.GET, - constants.GET_VOLUME_GROUP_DETAILS_URL.format( - self.server_ip, volume_group_id, - ), - payload=None, - querystring=helpers.prepare_querystring(constants.SELECT_ALL_VOL_GROUP), - ) - - def get_volume_group_by_name(self, volume_group_name): - """Get details of a volume group by name. - - :param volume_group_name: The name of the volume group - :type volume_group_name: str - :return: Details of the volume group - :rtype: dict - """ - LOG.info( "Getting volumegroup details by name: '%s'", volume_group_name) - return self.client.request( - constants.GET, - constants.GET_VOLUME_GROUP_BY_NAME_URL.format(self.server_ip), - payload=None, - querystring=helpers.prepare_querystring( - constants.SELECT_ALL_VOL_GROUP, - name=constants.EQUALS + volume_group_name, - ), - ) - - def modify_volume_group( - self, - volume_group_id, - name=None, - description=None, - is_write_order_consistent=None, - protection_policy_id=None, - ): - """Modify a volume group. - - :param volume_group_id: The id of the volume group - :type volume_group_id: str - :param name: (optional) The name of the volume group - :type name: str - :param description: (optional) The description of the VG - :type description: str - :param is_write_order_consistent: (optional) Indicate whether snapshot - sets of the volume group will be - write-order consistent. - :type is_write_order_consistent: bool - :param protection_policy_id: (optional) Unique identifier of the - protection policy to assign to a primary - or clone volume group. If an empty string - is specified, protection policy will be - removed from the volume group. - :type protection_policy_id: str - """ - LOG.info( "Modifying volumegroup: '%s'", volume_group_id) - payload = self._prepare_modify_vg_payload( - name, description, is_write_order_consistent, protection_policy_id, - ) - self.client.request( - constants.PATCH, - constants.MODIFY_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), - payload, - ) - - def _prepare_modify_vg_payload( - self, name, description, is_write_order_consistent, protection_policy_id, - ): - modify_vg_dict = {} - if name is not None: - modify_vg_dict["name"] = name - if description is not None: - modify_vg_dict["description"] = description - if is_write_order_consistent is not None: - modify_vg_dict["is_write_order_consistent"] = is_write_order_consistent - if protection_policy_id is not None: - modify_vg_dict["protection_policy_id"] = protection_policy_id - - return modify_vg_dict - - def delete_volume_group(self, volume_group_id): - """Delete a volume group. - - :param: volume_group_id: The volume group ID - :type: volume_group_id: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Deleting volumegroup: '%s'", volume_group_id) - return self.client.request( - constants.DELETE, - constants.DELETE_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), - payload=None, - ) - - def add_members_to_volume_group( - self, volume_group_id, volume_ids, force_internal=False, - ): - """Add members to volume group. - - :param volume_ids: The volume IDs to be added - :type volume_ids: list - :param force_internal: (optional) The force internal flag - :type force_internal: bool - :return: None if success else raise exception - :rtype: None - """ - LOG.info( - f"Adding volumes: '{volume_ids}' to volumegroup: '{volume_group_id}'", - ) - payload = self._prepare_add_members_to_volume_group_payload( - volume_ids, force_internal, - ) - return self.client.request( - constants.POST, - constants.ADD_MEMBERS_TO_VOLUME_GROUP_URL.format( - self.server_ip, volume_group_id, - ), - payload=payload, - ) - - def _prepare_add_members_to_volume_group_payload(self, volume_ids, force_internal): - add_members_to_vg_dict = {} - if volume_ids is not None: - add_members_to_vg_dict["volume_ids"] = volume_ids - if force_internal is not None: - add_members_to_vg_dict["force_internal"] = force_internal - - return add_members_to_vg_dict - - def remove_members_from_volume_group( - self, volume_group_id, volume_ids, force_internal=False, - ): - """Remove members from volume group. - - :param volume_ids: The list of volume IDs to be removed - :type volume_ids: str - :param force_internal: (optional) The force internal flag - :type force_internal: bool - :return: None if success else raise exception - :rtype: None - :rtype None or dict - """ - LOG.info( - f"Removing volumes: '{volume_ids}' from volumegroup: '{volume_group_id}'", - ) - payload = self._prepare_remove_members_from_volume_group_payload( - volume_ids, force_internal, - ) - return self.client.request( - constants.POST, - constants.REMOVE_MEMBERS_FROM_VOLUME_GROUP_URL.format( - self.server_ip, volume_group_id, - ), - payload=payload, - ) - - def _prepare_remove_members_from_volume_group_payload( - self, volume_ids, force_internal, - ): - remove_members_from_vg_dict = {} - if volume_ids is not None: - remove_members_from_vg_dict["volume_ids"] = volume_ids - if force_internal is not None: - remove_members_from_vg_dict["force_internal"] = force_internal - - return remove_members_from_vg_dict - - def get_nodes(self, filter_dict=None, all_pages=False): - """Returns a list of nodes. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :return: Nodes - :rtype: list of dict - """ - LOG.info( - f"Getting nodes with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ID_AND_NAME, filter_dict, - ) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_NODE.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def get_cluster_list(self): - """Returns a list of clusters. - - :return: Clusters - :rtype: list of dict - """ - LOG.info("Getting clusters") - return self.client.request( - constants.GET, - constants.GET_CLUSTER.format(self.server_ip), - payload=None, - querystring=constants.CLUSTER_DETAILS_QUERY, - ) - - def get_host_volume_mapping(self, volume_id): - """Get Host volume mapping details. - - :param volume_id: The Volume ID - :type volume_id: str - :return: Host volume mapping details - :rtype: dict - """ - LOG.info( "Getting host mapping with vol: '%s'", volume_id) - return self.client.request( - constants.GET, - constants.HOST_VOLUME_MAPPING_URL.format(self.server_ip), - payload=None, - querystring=helpers.prepare_querystring( - constants.SELECT_ALL_HOST_VOLUME_MAPPING, - volume_id=constants.EQUALS + volume_id, - ), - ) - - # NAS Server methods - - def get_nas_servers(self, filter_dict=None, all_pages=False): - """Get a list of nas servers. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :return: NAS servers - :rtype: list of dict - """ - LOG.info( - f"Getting nasservers with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ID_AND_NAME, filter_dict, - ) - LOG.info( "Querystring: %s", querystring) - return self.client.request( - constants.GET, - constants.GET_NAS_SERVER_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def get_nas_server_details(self, nas_server_id): - """Details of a Nas Server. - - :param nas_server_id: The NAS Server ID - :type nas_server_id: str - :return: NAS server details - :rtype: dict - """ - querystring = constants.SELECT_ALL_NAS_SERVER - if helpers.is_foot_hill_prime_or_higher(): - querystring = constants.FHP_NAS_QUERYSTRING - - LOG.info( "Getting nasserver details by ID: '%s'", nas_server_id) - return self.client.request( - constants.GET, - constants.GET_NAS_SERVER_DETAILS_URL.format(self.server_ip, nas_server_id), - payload=None, - querystring=querystring, - ) - - def get_nas_server_by_name(self, nas_server_name): - """Get details of a NAS Server by name. - - :param nas_server_name: The name of the NAS Server - :type nas_server_name: str - :return: NAS server details - :rtype: dict - """ - querystring = constants.SELECT_ALL_NAS_SERVER - if helpers.is_foot_hill_prime_or_higher(): - querystring = constants.FHP_NAS_QUERYSTRING - - LOG.info( "Getting nasserver details by name: '%s'", nas_server_name) - return self.client.request( - constants.GET, - constants.GET_NAS_SERVER_DETAILS_BY_NAME_URL.format(self.server_ip), - payload=None, - querystring=helpers.prepare_querystring( - querystring, name=constants.EQUALS + nas_server_name, - ), - ) - - def create_nasserver(self, payload): - """Create a NAS Server. - - :param payload: The payload to create the NAS Server - :type payload: dict - :return: NAS server ID on success else raise exception - :rtype: dict - """ - LOG.info( "Creating NAS server: '%s'", payload.get('name')) - if ( - "protection-policy" in payload - and not helpers.is_foot_hill_prime_or_higher() - ): - raise Exception( - "Protection policy is supported for PowerStore" - " version 3.0.0.0 and above.", - ) - return self.client.request( - constants.POST, - constants.CREATE_NAS_SERVER_URL.format(self.server_ip), - payload=payload, - ) - - def modify_nasserver(self, nasserver_id, modify_parameters): - """Modify NAS Server attributes. - - :param nasserver_id: The ID of the NAS Server - :type nasserver_id: str - :param modify_parameters: Attributes to be modified - :type modify_parameters: dict - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Modifying nasserver: '%s'", nasserver_id) - if modify_parameters: - payload = {} - for key, value in modify_parameters.items(): - if value is not None: - payload[key] = value - - if payload: - return self.client.request( - constants.PATCH, - constants.MODIFY_NAS_SERVER_URL.format( - self.server_ip, nasserver_id, - ), - payload=payload, - ) - - raise ValueError("Nothing to modify") - - def delete_nasserver(self, nasserver_id): - """Delete a NAS Server. - - :param nasserver_id: The ID of the NAS Server to delete - :type nasserver_id: str - :return: None on success else raise exception - :rtype: None - """ - LOG.info( "Deleting NAS server: '%s'", nasserver_id) - return self.client.request( - constants.DELETE, - constants.DELETE_NAS_SERVER_URL.format(self.server_ip, nasserver_id), - ) - - # NAS Server methods end - - # File System Methods - def get_file_systems(self, filter_dict=None, all_pages=False): - """Get a list of file systems. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - - :returns: File systems - :rtype: list of dict - """ - LOG.info( - f"Getting filesystems with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ID_AND_NAME, filter_dict, - ) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_FILE_SYSTEM_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def get_filesystem_details(self, filesystem_id): - """Details of a Filesystem. - - :param filesystem_id: The File System ID - :type filesystem_id: str - :returns: File system details - :rtype: dict - """ - LOG.info( "Getting filesystem details by ID: '%s'", filesystem_id) - querystring = constants.SELECT_ALL_FILESYSTEM - if helpers.is_foot_hill_prime_or_higher(): - querystring = constants.SELECT_ALL_FILESYSTEM_PRIME - return self.client.request( - constants.GET, - constants.GET_FILESYSTEM_DETAILS_URL.format(self.server_ip, filesystem_id), - payload=None, - querystring=querystring, - ) - - def get_filesystem_by_name(self, filesystem_name, nas_server_id): - """Get details of a filesystem by name. - - :param filesystem_name: The name of the File System - :type filesystem_name: str - :returns: File system details - :rtype: dict - """ - LOG.info( - "Getting filesystem details by name: '%s' and NAS Server: " - "'%s'" % (filesystem_name, nas_server_id), - ) - querystring = constants.SELECT_ALL_FILESYSTEM - if helpers.is_foot_hill_prime_or_higher(): - querystring = constants.SELECT_ALL_FILESYSTEM_PRIME - return self.client.request( - constants.GET, - constants.GET_FILESYSTEM_DETAILS_BY_NAME_URL.format(self.server_ip), - payload=None, - querystring=helpers.prepare_querystring( - querystring, - nas_server_id=constants.EQUALS + nas_server_id, - name=constants.EQUALS + filesystem_name, - ), - ) - - def create_filesystem(self, name, nas_server_id, size_total, advance_parameters): - """Create a filesystem. - - :param name: The name of the File System - :type name: str - :param nas_server_id: The ID of the NAS Server - :type name: str - :param size_total: Total size of the file system in bytes - :type name: str - :param advance_parameters: Advance attributes - :type advance_parameters: str - :return: Filesystem ID on success else raise exception - :rtype: dict - """ - LOG.info( "Creating filesystem: '%s'", name) - payload = {} - payload["name"] = name - payload["nas_server_id"] = nas_server_id - payload["size_total"] = size_total - - if advance_parameters: - for key, value in advance_parameters.items(): - if ( - key in constants.FILESYSTEM_PRIME - and not helpers.is_foot_hill_prime_or_higher() - ): - raise Exception( - key + " is supported for PowerStore version 3.0.0.0 and above.", - ) - payload[key] = value - return self.client.request( - constants.POST, - constants.CREATE_FILESYSTEM_URL.format(self.server_ip), - payload=payload, - ) - - def delete_filesystem(self, filesystem_id): - """Delete a File System. - - :param filesystem_id: The FileSystem ID - :type filesystem_id: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Deleting filesystem: '%s'", filesystem_id) - return self.client.request( - constants.DELETE, - constants.DELETE_FILESYSTEM_URL.format(self.server_ip, filesystem_id), - payload=None, - ) - - def get_snapshots_filesystem(self, filesystem_id): - """Get Snapshots of a Filesystem. - - :param filesystem_id: The File System ID - :type filesystem_id: str - :returns: Snapshots of a FileSystem - :rtype: list - """ - LOG.info( "Getting snapshots of filesystem: '%s'", filesystem_id) - return self.client.request( - constants.GET, - constants.GET_SNAPSHOTS_FILESYSTEM_URL.format(self.server_ip), - querystring=helpers.prepare_querystring( - constants.SELECT_ID_AND_NAME, parent_id=constants.EQUALS + filesystem_id, - ), - ) - - def modify_filesystem(self, filesystem_id, modify_parameters): - """Modify FileSystem attributes. - :param filesystem_id: The ID of the FileSystem - :type filesystem_id: str - :param modify_parameters: Attributes to be modified - :type modify_parameters: dict - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Modifying filesystem: '%s'", filesystem_id) - if modify_parameters: - payload = {} - for key, value in modify_parameters.items(): - if ( - key in constants.FILESYSTEM_PRIME - and not helpers.is_foot_hill_prime_or_higher() - ): - raise Exception( - key + " is supported for PowerStore version 3.0.0.0 and above.", - ) - if value is not None: - payload[key] = value - - if payload: - return self.client.request( - constants.PATCH, - constants.MODIFY_FILESYSTEM_URL.format( - self.server_ip, filesystem_id, - ), - payload=payload, - ) - - raise ValueError("Nothing to modify") - - # File System methods end - - # NFS Export Methods - def get_nfs_exports(self, filter_dict=None, all_pages=False): - """Get a list of nfs exports. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :returns: NFS exports - :rtype: list of dict - """ - LOG.info( - f"Getting nfsexports with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ID_AND_NAME, filter_dict, - ) - LOG.info( "Querystring: %s", querystring) - return self.client.request( - constants.GET, - constants.GET_NFS_EXPORT_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def get_nfs_export_details(self, nfs_export_id): - """Get details of a particular NFS Export. - - :param nfs_export_id: The ID of the NFS Export - :type nfs_export_id: str - :returns: NFS Export details - :rtype: dict - """ - LOG.info( "Getting nfsexport details by ID: '%s'", nfs_export_id) - return self.client.request( - constants.GET, - constants.GET_NFS_EXPORT_DETAILS_URL.format(self.server_ip, nfs_export_id), - querystring=constants.SELECT_ALL_NFS_EXPORT, - ) - - def get_nfs_export_details_by_name(self, nfs_export_name): - """Get details of a NFS Export by name. - - :param nfs_export_name: The name of the NFS Export - :type nfs_export_name: str - :returns: NFS Export details - :rtype: list - """ - LOG.info( "Getting nfsexport details by name: '%s'", nfs_export_name) - return self.client.request( - constants.GET, - constants.GET_NFS_EXPORT_DETAILS_BY_NAME_URL.format(self.server_ip), - querystring=helpers.prepare_querystring( - constants.SELECT_ALL_NFS_EXPORT, name=constants.EQUALS + nfs_export_name, - ), - ) - - def create_nfs_export(self, file_system_id, path, name, nfs_other_params): - """Create NFS Export of filesystem. - - :param file_system_id: The ID of the filesystem on which NFS Export - will be created - :type file_system_id: str - :param path: Local path to export relative to the NAS server root - :type path: str - :param name: The name of the NFS Export - :type name: str - :param nfs_other_params: Dictionary containing attributes with - which NFS Export will be created - :type nfs_other_params: dict - :returns: The ID of the NFS export - :rtype: dict - """ - LOG.info( "Creating NFSExport: '%s'", name) - payload = {} - payload["name"] = name - payload["file_system_id"] = file_system_id - payload["path"] = path - if nfs_other_params: - payload.update(nfs_other_params) - return self.client.request( - constants.POST, - constants.CREATE_NFS_EXPORT_URL.format(self.server_ip), - payload=payload, - ) - - def modify_nfs_export(self, nfs_export_id, nfs_other_params): - """Modify NFS Export attributes. - - :param nfs_export_id: The ID of the NFS Export - :type nfs_export_id: str - :param nfs_other_params: Dictionary containing attributes to be - modified of the NFS Export - :type nfs_other_params: dict - :return: None if success else raise exception - :rtype: None - """ - LOG.info( - f"Modifying nfsexport: '{nfs_export_id}' with params: '{nfs_other_params}'", - ) - return self.client.request( - constants.PATCH, - constants.MODIFY_NFS_EXPORT_URL.format(self.server_ip, nfs_export_id), - payload=nfs_other_params, - ) - - def delete_nfs_export(self, nfs_export_id): - """Delete NFS Export. - - :param nfs_export_id: The ID of the NFS Export - :type nfs_export_id: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Deleting nfsexport: '%s'", nfs_export_id) - return self.client.request( - constants.DELETE, - constants.DELETE_NFS_EXPORT_URL.format(self.server_ip, nfs_export_id), - ) - - # NFS Export Method ENDs - - # SMB Share Methods - def get_smb_shares(self, filter_dict=None, all_pages=False): - """Get a list of smb shares. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - - :returns: SMB shares - :rtype: list of dict - """ - LOG.info( - f"Getting smbshares with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ALL_SMB_SHARE, filter_dict, - ) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_SMB_SHARE_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def get_smb_share_by_name(self, share_name): - """Get details of a SMB Share with its name. - - :param share_name: The name of the smb share. - :type share_name: str - :return: SMB share details - :rtype: dict - """ - LOG.info( "Getting smbshare details by name: '%s'", share_name) - return self.client.request( - constants.GET, - constants.GET_SMB_SHARE_LIST_URL.format(self.server_ip), - querystring=helpers.prepare_querystring( - constants.SELECT_ALL_SMB_SHARE, name=constants.EQUALS + share_name, - ), - ) - - def get_smb_share(self, share_id): - """Get details of a SMB Share with its id. - - :param share_id: The Id of the SMB share. - :type share_id: str - :return: SMB share details - :rtype: dict - """ - LOG.info( "Getting smbshare details by ID: '%s'", share_id) - return self.client.request( - constants.GET, - constants.GET_SMB_SHARE_DETAILS_URL.format(self.server_ip, share_id), - querystring=constants.SELECT_ALL_SMB_SHARE, - ) - - def create_smb_share(self, file_system_id, path, name, **kw_smb_other_params): - """Create SMB share - - :param file_system_id: The ID of the File System. - :type file_system_id: str - :param path: Local path to the file system or any existing sub-folder - of the file system that is shared over the network. - :type path: str - :param name: Name of the SMB Share. - :type name: str - :param kw_smb_other_params: Advance parameters. - :type name: dict - :return: The ID of the smb share if successful else error. - :rtype: dict - """ - LOG.info( "Creating smbshare: '%s'", name) - payload = {} - payload["name"] = name - payload["file_system_id"] = file_system_id - payload["path"] = path - if kw_smb_other_params: - for key, value in kw_smb_other_params.items(): - payload[key] = value - return self.client.request( - constants.POST, - constants.CREATE_SMB_SHARE_URL.format(self.server_ip), - payload=payload, - ) - - def update_smb_share(self, id, **kw_smb_other_params): - """Modify a SMB Share. - - :param id: The ID of SMB Share. - :param kw_smb_other_params: Parameters which are to be modified. - :return: None if success else raise exception - :rtype: None - """ - LOG.info( - f"Modifying smbshare: '{id}' with params: '{kw_smb_other_params}'", - ) - return self.client.request( - constants.PATCH, - constants.MODIFY_SMB_SHARE_URL.format(self.server_ip, id), - payload=kw_smb_other_params, - ) - - def delete_smb_share(self, share_id): - """Delete a SMB Share. - - :param share_id: The ID of the SMB share. - :type share_id: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Deleting smbshare: '%s'", share_id) - return self.client.request( - constants.DELETE, - constants.DELETE_SMB_SHARE_URL.format(self.server_ip, share_id), - ) - - # SMB Share Methods End - - # ACL Methods - - def get_acl(self, share_id): - """Retrieves the Access Control List (ACL) details for a given share ID. - - :param share_id: The ID of the share for which to retrieve the ACL details. - :type share_id: str - :return: The response from the client's request to retrieve the ACL details. - :rtype: dict - """ - LOG.info( "Getting ACL details: '%s'", share_id) - return self.client.request( - constants.POST, - constants.GET_ACL_DETAILS.format(self.server_ip, share_id), - ) - - def set_acl(self, share_id, add_aces=None, remove_aces=None): - """Sets the access control list (ACL) for a given share. - - Args: - share_id (str): The ID of the share. - add_aces (list, optional): A list of access control entries - (ACEs) to add to the ACL. Defaults to None. - remove_aces (list, optional): A list of access control entries - (ACEs) to remove from the ACL. Defaults to None. - - Returns: - dict: The response from the server after setting the ACL. - - """ - payload = {} - if add_aces: - payload["add_aces"] = add_aces - if remove_aces: - payload["remove_aces"] = remove_aces - return self.client.request( - constants.POST, - constants.SET_ACL_DETAILS.format(self.server_ip, share_id), - payload=payload, - ) - - # ACL Methods End - - # FS Quota Methods - def get_file_tree_quotas(self, filter_dict=None, all_pages=False): - """Get a list of file tree quotas. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :returns: File tree quotas - :rtype: list of dict - """ - LOG.info( - f"Getting tree quotas with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring( - constants.SELECT_ID_AND_PATH, filter_dict, - ) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_TREE_QUOTA_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def get_file_user_quotas(self, filter_dict=None, all_pages=False): - """Get a list of file user quotas. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :returns: File user quotas - :rtype: list of dict - """ - LOG.info( - f"Getting user quotas with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring(filter_dict) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_USER_QUOTA_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - def get_tree_quota(self, tree_quota_id, path=None, file_system_id=None): - """Get details of Tree Quota either by its ID or - by path and the filesystem_id. - - :param tree_quota_id: The Id of the Tree Quota. - :type tree_quota_id: str - :param path: (optional) Path of the tree relative to the root of the - associated filesystem. - :type path: str - :param file_system_id: (optional) ID of the associated filesystem. - :type file_system_id: str - :return: Tree quota details - :rtype: dict - """ - if tree_quota_id: - LOG.info( "Getting tree quota details by ID: '%s'", tree_quota_id) - return self.client.request( - constants.GET, - constants.GET_TREE_QUOTA_DETAILS_URL.format( - self.server_ip, tree_quota_id, - ), - querystring=constants.SELECT_ALL_TREE_QUOTA, - ) - LOG.info( - f"Getting tree quota details by path: '{tree_quota_id}' and fs_id: '{file_system_id}'", - ) - return self.client.request( - constants.GET, - constants.GET_TREE_QUOTA_LIST_URL.format(self.server_ip), - querystring=helpers.prepare_querystring( - constants.SELECT_ALL_TREE_QUOTA, - path=constants.EQUALS + path, - file_system_id=constants.EQUALS + file_system_id, - ), - ) - - def get_user_quota(self, user_quota_id, query_params=None): - """Get details of User Quota with its id or by other user quota - parameters. - - :param user_quota_id: The Id of the User Quota. - :type user_quota_id: str - :param query_params: (optional) Other parameters of User Quota - :type query_params: dict - :return: User Quota details - :rtype: dict - """ - if user_quota_id: - LOG.info( "Getting user quota details by ID: '%s'", user_quota_id) - return self.client.request( - constants.GET, - constants.GET_USER_QUOTA_DETAILS_URL.format( - self.server_ip, user_quota_id, - ), - querystring=constants.SELECT_ALL_USER_QUOTA, - ) - if query_params: - for key, value in query_params.items(): - query_params[key] = constants.EQUALS + value - LOG.info( "Getting user quota details by params: '%s'", query_params) - return self.client.request( - constants.GET, - constants.GET_USER_QUOTA_LIST_URL.format(self.server_ip), - querystring=helpers.prepare_querystring( - constants.SELECT_ALL_USER_QUOTA, query_params, - ), - ) - - def create_tree_quota(self, file_system_id, path, tree_quota_params): - """Create a Tree Quota. - - :param file_system_id: The ID of the File System. - :type file_system_id: str - :param path: Path relative to the root of the associated filesystem. - :type path: str - :param tree_quota_params: Remaining Tree Quota parameters. - :type tree_quota_params: dict - :return: The ID of the Tree Quota if successful else error. - :rtype: dict - """ - LOG.info( "Creating tree quota on filesystem ID: '%s'", file_system_id) - payload = {} - payload["file_system_id"] = file_system_id - payload["path"] = path - if tree_quota_params: - payload.update(tree_quota_params) - return self.client.request( - constants.POST, - constants.CREATE_TREE_QUOTA_URL.format(self.server_ip), - payload=payload, - ) - - def create_user_quota(self, file_system_id, user_quota_params): - """Create a User Quota. - - :param file_system_id: The ID of the File System. - :type file_system_id: str - :param user_quota_params: Remaining User Quota parameters. - :type user_quota_params: dict - :return: The ID of the User Quota if successful else error. - :rtype: dict - """ - LOG.info( "Creating user quota on filesystem ID: '%s'", file_system_id) - payload = {} - payload["file_system_id"] = file_system_id - if user_quota_params: - payload.update(user_quota_params) - return self.client.request( - constants.POST, - constants.CREATE_USER_QUOTA_URL.format(self.server_ip), - payload=payload, - ) - - def update_tree_quota(self, tree_quota_id, tree_quota_params): - """Update a Tree Quota. - - :param tree_quota_id: The ID of Tree Quota. - :type tree_quota_id: str - :param tree_quota_params: Tree Quota parameters to be modified. - :type tree_quota_params: dict - :return: None if success else raise exception - :rtype: None - """ - LOG.info( - f"Modifying tree quota: '{tree_quota_id}' with params: '{tree_quota_params}'", - ) - return self.client.request( - constants.PATCH, - constants.MODIFY_TREE_QUOTA_URL.format(self.server_ip, tree_quota_id), - payload=tree_quota_params, - ) - - def update_user_quota(self, user_quota_id, user_quota_params): - """Update a User Quota. - - :param user_quota_id: The ID of User Quota. - :type user_quota_id: str - :param user_quota_params: User Quota parameters to be modified. - :type user_quota_params: dict - :return: None if success else raise exception - :rtype: None - """ - LOG.info( - f"Modifying user quota: '{user_quota_id}' with params: '{user_quota_params}'", - ) - return self.client.request( - constants.PATCH, - constants.MODIFY_USER_QUOTA_URL.format(self.server_ip, user_quota_id), - payload=user_quota_params, - ) - - def delete_tree_quota(self, tree_quota_id): - """Delete a Tree Quota. - :param tree_quota_id: The ID of the Tree Quota. - :type tree_quota_id: str - :return: None if success else raise exception - :rtype: None - """ - LOG.info( "Deleting tree quota: '%s'", tree_quota_id) - return self.client.request( - constants.DELETE, - constants.DELETE_TREE_QUOTA_URL.format(self.server_ip, tree_quota_id), - ) - - # FS Quota Methods end - - # Job Methods start - - def get_job_details(self, job_id): - """Get details of a Job with its id. - :param job_id: The Id of job. - :type job_id: str - :return: Job details - :rtype: dict - """ - LOG.info( "Getting job details: '%s'", job_id) - querystring = constants.JOB_DETAILS_QUERY - if helpers.is_foot_hill_or_higher(): - querystring = constants.FHC_JOB_DETAILS_QUERY - return self.client.request( - constants.GET, - constants.GET_JOB_DETAILS_URL.format(self.server_ip, job_id), - querystring=querystring, - ) - - # Job Methods end - - # AD methods start - - def get_file_ads(self, filter_dict=None, all_pages=False): - """Get a list of active directories. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :returns: active directories - :rtype: list of dict - """ - LOG.info( - f"Getting active directories with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring(filter_dict) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_AD_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - # AD Methods end - - # LDAP method start - - def get_file_ldaps(self, filter_dict=None, all_pages=False): - """Get a list of ldap. - - :param filter_dict: (optional) Filter detail - :type filter_dict: dict - :param all_pages: (optional) Indicates whether to return all element - or not - :type all_pages: bool - :returns: ldap - :rtype: list of dict - """ - LOG.info( - f"Getting ldap with filter: '{filter_dict}' and all_pages: {all_pages}", - ) - querystring = helpers.prepare_querystring(filter_dict) - LOG.info( "Querystring: '%s'", querystring) - return self.client.request( - constants.GET, - constants.GET_LDAP_LIST_URL.format(self.server_ip), - payload=None, - querystring=querystring, - all_pages=all_pages, - ) - - # LDAP method end +# Copyright: (c) 2024, Dell Technologies + +"""Collection of provisioning related functions for PowerStore""" + +from PyPowerStore.client import Client +from PyPowerStore.utils import constants, helpers + +# TODO: kept LOG as global for now will improve it to avoid overriding +LOG = helpers.get_logger(__name__) + + +class Provisioning: + """Provisioning related functionality for PowerStore.""" + + def __init__( + self, + server_ip, + username, + password, + verify, + application_type, + timeout, + enable_log=False, + port_no=None, + ): + """Initializes Provisioning Class + + :param server_ip: The array IP + :type server_ip: str + :param port_no: The port number + :type port_no: int + :param username: array username + :type username: str + :param password: array password + :type password: str + :param verify: Whether the SSL cert will be verified + :type verify: bool + :param application_type: Application Type + :type application_type: str + :param timeout: How long to wait for the server to send data before + giving up + :type timeout: float + :param enable_log: (optional) Whether to enable log or not + :type enable_log: bool + """ + global LOG + if port_no is None: + port_no = 443 + self.server_ip = server_ip + ":" + str(port_no) + self.client = Client( + username, password, verify, application_type, timeout, enable_log=enable_log, + ) + LOG = helpers.get_logger(__name__, enable_log=enable_log) + helpers.set_provisioning_obj(self) + + def get_array_version(self): + """Get the software version of this array. + + :return: software version details + :rtype: str + """ + LOG.info("Getting the software version of this array") + querystring = helpers.prepare_querystring(constants.SELECT_VERSION) + LOG.info( "Querystring: '%s'", querystring) + sw_versions = self.client.request( + constants.GET, + constants.GET_SOFTWARE_VERSION.format(self.server_ip), + payload=None, + querystring=querystring, + ) + version = None + if sw_versions and len(sw_versions) > 0: + version = sw_versions[0]["release_version"] + return version + + def create_volume( + self, + name, + size, + description=None, + volume_group_id=None, + protection_policy_id=None, + performance_policy_id=None, + app_type=None, + app_type_other=None, + appliance_id=None, + ): + """Create a volume. + + :param name: The name of the volume + :param size: The size of the volume + :param description: (optional) The description given to the volume + :param volume_group_id: (optional) The volume group ID + :param protection_policy_id: (optional) The protection policy ID + :param performance_policy_id: (optional) The performance policy ID + :param app_type: (optional) The application type + :param app_type_other: (optional) Describes application type when + app_type is set to other + :param appliance_id: (optional) The appliance ID + """ + if app_type is not None and not helpers.is_malka_or_higher(): + raise Exception( + "'app_type' parameter is supported only from " + "Powerstore version 2.1.0.0 onwards", + ) + + LOG.info( "Creating volume: '%s'", name) + payload = self._prepare_create_volume_payload( + name, + size, + description, + volume_group_id, + protection_policy_id, + performance_policy_id, + app_type, + app_type_other, + appliance_id, + ) + self.client.request( + constants.POST, constants.VOLUME_CREATE_URL.format(self.server_ip), payload, + ) + + def _prepare_create_volume_payload( + self, + name, + size, + description, + volume_group_id, + protection_policy_id, + performance_policy_id, + app_type, + app_type_other, + appliance_id, + ): + create_volume_dict = {} + if name is not None: + create_volume_dict["name"] = name + if size is not None: + create_volume_dict["size"] = size + if description is not None: + create_volume_dict["description"] = description + if volume_group_id is not None: + create_volume_dict["volume_group_id"] = volume_group_id + if protection_policy_id is not None: + create_volume_dict["protection_policy_id"] = protection_policy_id + if performance_policy_id is not None: + create_volume_dict["performance_policy_id"] = performance_policy_id + if app_type is not None: + create_volume_dict["app_type"] = app_type + if app_type_other is not None: + create_volume_dict["app_type_other"] = app_type_other + if appliance_id is not None: + create_volume_dict["appliance_id"] = appliance_id + + return create_volume_dict + + def delete_volume(self, volume_id): + """Delete a volume. + + :param volume_id: The Volume ID + :type volume_id: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Deleting volume: '%s'", volume_id) + return self.client.request( + constants.DELETE, + constants.DELETE_VOLUME_URL.format(self.server_ip, volume_id), + payload=None, + ) + + def modify_volume( + self, + volume_id, + name=None, + description=None, + size=None, + protection_policy_id=None, + performance_policy_id=None, + app_type=None, + app_type_other=None, + ): + """Modify a volume. + + :param volume_id: The volume ID + :type volume_id: str + :param name: The name of the volume + :type name: str + :param description: The description of the volume + :type description: str + :param size: The size of the volume + :type size: str + :param protection_policy_id: The protection policy ID + :type protection_policy_id: str + :param performance_policy_id: The performance policy ID + :type performance_policy_id: str + :param app_type: The application type + :type app_type: str + :param app_type_other: Describes application type when + app_type is set to other + :return: None if success else raise exception + :rtype: None + """ + if app_type is not None and not helpers.is_malka_or_higher(): + raise Exception( + "'app_type' parameter is supported only from " + "Powerstore version 2.1.0.0 onwards", + ) + + LOG.info( "Modifying volume: '%s'", volume_id) + payload = self._prepare_modify_volume_payload( + name, + description, + size, + protection_policy_id, + performance_policy_id, + app_type, + app_type_other, + ) + return self.client.request( + constants.PATCH, + constants.MODIFY_VOLUME_URL.format(self.server_ip, volume_id), + payload, + ) + + def _prepare_modify_volume_payload( + self, + name=None, + description=None, + size=None, + protection_policy_id=None, + performance_policy_id=None, + app_type=None, + app_type_other=None, + ): + modify_volume_dict = {} + if name is not None: + modify_volume_dict["name"] = name + if description is not None: + modify_volume_dict["description"] = description + if size is not None: + modify_volume_dict["size"] = size + if protection_policy_id is not None: + modify_volume_dict["protection_policy_id"] = protection_policy_id + if performance_policy_id is not None: + modify_volume_dict["performance_policy_id"] = performance_policy_id + if app_type is not None: + modify_volume_dict["app_type"] = app_type + if app_type_other is not None: + modify_volume_dict["app_type_other"] = app_type_other + + return modify_volume_dict + + def clone_volume( + self, + volume_id, + name=None, + description=None, + host_id=None, + host_group_id=None, + logical_unit_number=None, + protection_policy_id=None, + performance_policy_id=None, + ): + """Clone a volume. + + :param volume_id: The volume ID + :type volume_id: str + :param name: Name of the clone + :type name: str + :param description: Description of the clone + :type description: str + :param host_id: Unique identifier of the host to be attached to the clone. + :type host_id: str + :param host_group_id: Unique identifier of the host group to be attached to the clone. + :type host_group_id: str + :param logical_unit_number: Optional logical unit number when creating a mapped volume. + :type logical_unit_number: int + :param protection_policy_id: The protection policy ID + :type protection_policy_id: str + :param performance_policy_id: The performance policy ID + :type performance_policy_id: str + :return: 'id' Unique identifier of the new clone volume if success else raise exception + :rtype: dict + """ + LOG.info( "Cloning the volume: '%s'", volume_id) + payload = self._prepare_clone_volume_payload( + name, + description, + host_id, + host_group_id, + logical_unit_number, + protection_policy_id, + performance_policy_id, + ) + return self.client.request( + constants.POST, + constants.CLONE_VOLUME_URL.format(self.server_ip, volume_id), + payload, + ) + + def _prepare_clone_volume_payload( + self, + name=None, + description=None, + host_id=None, + host_group_id=None, + logical_unit_number=None, + protection_policy_id=None, + performance_policy_id=None, + ): + clone_volume_dict = {} + if name is not None: + clone_volume_dict["name"] = name + if description is not None: + clone_volume_dict["description"] = description + if host_id is not None: + clone_volume_dict["host_id"] = host_id + if host_group_id is not None: + clone_volume_dict["host_group_id"] = host_group_id + if logical_unit_number is not None: + clone_volume_dict["logical_unit_number"] = logical_unit_number + if protection_policy_id is not None: + clone_volume_dict["protection_policy_id"] = protection_policy_id + if performance_policy_id is not None: + clone_volume_dict["performance_policy_id"] = performance_policy_id + + return clone_volume_dict + + def refresh_volume( + self, + volume_id, + volume_id_to_refresh_from=None, + create_backup_snap=None, + backup_snap_name=None, + backup_snap_description=None, + backup_snap_expiration_timestamp=None, + backup_snap_performance_policy_id=None, + ): + """Refresh a volume. + + :param volume_id: The volume ID + :type volume_id: str + :param volume_id_to_refresh_from: Unique identifier of the source volume that will be used for the refresh operation + :type volume_id_to_refresh_from: str + :param create_backup_snap: Indicates whether a backup snapshot of the target volume will be created before it is refreshed from the source volume + :type create_backup_snap: bool + :param backup_snap_name: Name of the backup snapshot to be created. The default name of the volume snapshot is the date and time when the snapshot is taken + :type backup_snap_name: str + :param backup_snap_description: Description of the backup snapshot. + :type backup_snap_description: str + :param backup_snap_performance_policy_id: Unique identifier of the performance policy assigned to the snapshot. + :type backup_snap_performance_policy_id: str + :param backup_snap_expiration_timestamp: Time at which the backup snapshot will expire. + :type backup_snap_expiration_timestamp: str + :return: 'backup_snapshot_id' Unique identifier of the backup snapshot of the target volume, if one is created prior to the refresh operation. + :rtype: dict + """ + LOG.info( "Refreshing the volume: '%s'", volume_id) + payload = self._prepare_refresh_volume_payload( + volume_id_to_refresh_from, + create_backup_snap, + backup_snap_name, + backup_snap_description, + backup_snap_expiration_timestamp, + backup_snap_performance_policy_id, + ) + return self.client.request( + constants.POST, + constants.REFRESH_VOLUME_URL.format(self.server_ip, volume_id), + payload, + ) + + def _prepare_refresh_volume_payload( + self, + volume_id_to_refresh_from=None, + create_backup_snap=None, + backup_snap_name=None, + backup_snap_description=None, + backup_snap_expiration_timestamp=None, + backup_snap_performance_policy_id=None, + ): + refresh_volume_dict = {} + if volume_id_to_refresh_from is not None: + refresh_volume_dict["from_object_id"] = volume_id_to_refresh_from + if create_backup_snap is not None: + refresh_volume_dict["create_backup_snap"] = create_backup_snap + + refresh_volume_dict["backup_snap_profile"] = {} + if backup_snap_name is not None: + refresh_volume_dict["backup_snap_profile"]["name"] = backup_snap_name + if backup_snap_description is not None: + refresh_volume_dict["backup_snap_profile"][ + "description" + ] = backup_snap_description + if backup_snap_expiration_timestamp is not None: + refresh_volume_dict["backup_snap_profile"][ + "expiration_timestamp" + ] = backup_snap_expiration_timestamp + if backup_snap_performance_policy_id is not None: + refresh_volume_dict["backup_snap_profile"][ + "performance_policy_id" + ] = backup_snap_performance_policy_id + + return refresh_volume_dict + + def restore_volume( + self, + volume_id, + snap_id_to_restore_from=None, + create_backup_snap=None, + backup_snap_name=None, + backup_snap_description=None, + backup_snap_expiration_timestamp=None, + backup_snap_performance_policy_id=None, + ): + """Restore a volume. + + :param volume_id: The volume ID + :type volume_id: str + :param snap_id_to_restore_from: Unique identifier of the source snapshot that will be used for the restore operation. + :type snap_id_to_restore_from: str + :param create_backup_snap: Indicates whether a backup snapshot of the target volume will be created before it is restored from the snapshot. + :type create_backup_snap: bool + :param backup_snap_name: Name of the backup snapshot to be created. The default name of the volume snapshot is the date and time when the snapshot is taken + :type backup_snap_name: str + :param backup_snap_description: Description of the backup snapshot. + :type backup_snap_description: str + :param backup_snap_performance_policy_id: Unique identifier of the performance policy assigned to the snapshot. + :type backup_snap_performance_policy_id: str + :param backup_snap_expiration_timestamp: Time at which the backup snapshot will expire. + :type backup_snap_expiration_timestamp: str + :return: 'backup_snapshot_id' Unique identifier of the backup snapshot of the target volume, if one is created prior to the restore operation. + :rtype: dict + """ + LOG.info( "Restoring the volume: '%s'", volume_id) + payload = self._prepare_restore_volume_payload( + snap_id_to_restore_from, + create_backup_snap, + backup_snap_name, + backup_snap_description, + backup_snap_expiration_timestamp, + backup_snap_performance_policy_id, + ) + return self.client.request( + constants.POST, + constants.RESTORE_VOLUME_URL.format(self.server_ip, volume_id), + payload, + ) + + def _prepare_restore_volume_payload( + self, + snap_id_to_restore_from=None, + create_backup_snap=None, + backup_snap_name=None, + backup_snap_description=None, + backup_snap_expiration_timestamp=None, + backup_snap_performance_policy_id=None, + ): + refresh_volume_dict = {} + if snap_id_to_restore_from is not None: + refresh_volume_dict["from_snap_id"] = snap_id_to_restore_from + if create_backup_snap is not None: + refresh_volume_dict["create_backup_snap"] = create_backup_snap + + refresh_volume_dict["backup_snap_profile"] = {} + if backup_snap_name is not None: + refresh_volume_dict["backup_snap_profile"]["name"] = backup_snap_name + if backup_snap_description is not None: + refresh_volume_dict["backup_snap_profile"][ + "description" + ] = backup_snap_description + if backup_snap_expiration_timestamp is not None: + refresh_volume_dict["backup_snap_profile"][ + "expiration_timestamp" + ] = backup_snap_expiration_timestamp + if backup_snap_performance_policy_id is not None: + refresh_volume_dict["backup_snap_profile"][ + "performance_policy_id" + ] = backup_snap_performance_policy_id + + return refresh_volume_dict + + def clone_filesystem(self, filesystem_id, advance_parameters): + """Clone a filesystem. + + :param filesystem_id: The filesystem ID + :type filesystem_id: str + :param advance_parameters: Advance attributes + :type advance_parameters: str + :return: Unique identifier of the new instance created if success else raise exception + :rtype: dict + """ + LOG.info( "Cloning the filesystem: '%s'", filesystem_id) + payload = {} + + if advance_parameters: + for key, value in advance_parameters.items(): + if ( + key in constants.FILESYSTEM_PRIME + and not helpers.is_foot_hill_prime_or_higher() + ): + raise Exception( + key + " is supported for PowerStore version 3.0.0.0 and above.", + ) + payload[key] = value + return self.client.request( + constants.POST, + constants.CLONE_FILESYSTEM_URL.format(self.server_ip, filesystem_id), + payload, + ) + + def restore_filesystem(self, snapshot_id, backup_snap_name=None): + """Restore a filesystem. + + :param snapshot_id: Unique identifier of the file system snapshot. + :type snapshot_id: str + :param backup_snap_name: Name of the backup snap to be created before the restore operation occurs. If no name is specified, no backup copy will be made. + :type backup_snap_name: str + :return: Unique identifier of the backup snapshot set or None if backup_snap_name is None + if success else raise exception + :rtype: dict + """ + LOG.info( "Restoring the filesystem from snapshot: '%s'", snapshot_id) + payload = {} + if backup_snap_name is not None: + payload["copy_name"] = backup_snap_name + return self.client.request( + constants.POST, + constants.RESTORE_FILESYSTEM_URL.format(self.server_ip, snapshot_id), + payload, + ) + + def refresh_filesystem(self, snapshot_id): + """Refresh a filesystem. + + :param snapshot_id: Unique identifier of the file system snapshot. + :type snapshot_id: str + :return: None if success else raise exception. + :rtype: None + """ + LOG.info( "Refreshing the filesystem from snapshot: '%s'", snapshot_id) + return self.client.request( + constants.POST, + constants.REFRESH_FILESYSTEM_URL.format(self.server_ip, snapshot_id), + ) + + def add_protection_policy_for_volume(self, volume_id, protection_policy_id): + """Add protection policy for volume. + + :param volume_id: The volume ID + :type volume_id: str + :param protection_policy_id: The protection policy ID + :type protection_policy_id: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( + f"Adding protection policy: '{protection_policy_id}' for volume: '{volume_id}'", + ) + payload = self._prepare_modify_volume_payload( + protection_policy_id=protection_policy_id, + ) + return self.client.request( + constants.PATCH, + constants.MODIFY_VOLUME_URL.format(self.server_ip, volume_id), + payload, + ) + + def remove_protection_policy_for_volume(self, volume_id): + """Remove protection policy for volume. + + :param volume_id: The volume ID + :type volume_id: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Removing protection policy for volume: '%s'", volume_id) + payload = {"protection_policy_id": ""} + return self.client.request( + constants.PATCH, + constants.MODIFY_VOLUME_URL.format(self.server_ip, volume_id), + payload, + ) + + def map_volume_to_host(self, volume_id, host_id=None, logical_unit_number=None): + """Map a volume to a Host. + + :param volume_id: The volume ID + :type volume_id: str + :param host_id: (optional) The host ID + :type host_id: str + :param logical_unit_number: (optional) The logical unit number + :type logical_unit_number: str + """ + LOG.info( "Mapping volume: '%s' to host", volume_id) + payload = self._prepare_map_vol_to_host_payload(host_id, logical_unit_number) + self.client.request( + constants.POST, + constants.MAP_VOLUME_TO_HOST_URL.format(self.server_ip, volume_id), + payload, + ) + + def _prepare_map_vol_to_host_payload(self, host_id, logical_unit_number): + map_volume_to_host_dict = {} + if host_id is not None: + map_volume_to_host_dict["host_id"] = host_id + if logical_unit_number is not None: + map_volume_to_host_dict["logical_unit_number"] = logical_unit_number + + return map_volume_to_host_dict + + def map_volume_to_host_group( + self, volume_id, host_group_id=None, logical_unit_number=None, + ): + """Map a volume to a Host. + + :param volume_id: The volume ID + :type volume_id: str + :param host_group_id: (optional) The host group ID + :type host_group_id: str + :param logical_unit_number: (optional) The logical unit number + :type logical_unit_number: str + """ + LOG.info( "Mapping volume: '%s' to host group", volume_id) + payload = self._prepare_map_vol_to_host_grp_payload( + host_group_id, logical_unit_number, + ) + self.client.request( + constants.POST, + constants.MAP_VOLUME_TO_HOST_URL.format(self.server_ip, volume_id), + payload, + ) + + def _prepare_map_vol_to_host_grp_payload(self, host_grp_id, logical_unit_number): + map_volume_to_host_dict = {} + if host_grp_id is not None: + map_volume_to_host_dict["host_group_id"] = host_grp_id + if logical_unit_number is not None: + map_volume_to_host_dict["logical_unit_number"] = logical_unit_number + + return map_volume_to_host_dict + + def unmap_volume_from_host(self, volume_id, host_id): + """Unmap a Volume from a Host. + + :param volume_id: The volume ID + :type volume_id: str + :param host_id: The host ID + :type host_id: str + """ + LOG.info( "Unmapping volume: '%s' from host: '%s'", volume_id, host_id) + payload = self._prepare_unmap_vol_from_host_payload(host_id) + self.client.request( + constants.POST, + constants.UNMAP_VOLUME_FROM_HOST_URL.format(self.server_ip, volume_id), + payload, + ) + + def _prepare_unmap_vol_from_host_payload(self, host_id): + unmap_vol_from_host_dict = {} + if host_id is not None: + unmap_vol_from_host_dict["host_id"] = host_id + + return unmap_vol_from_host_dict + + def unmap_volume_from_host_group(self, volume_id, host_group_id): + """Unmap a Volume from a Host. + + :param volume_id: The volume ID + :type volume_id: str + :param host_group_id: The host group ID + :type host_group_id: str + """ + LOG.info( + f"Unmapping volume: '{volume_id}' from host group: '{host_group_id}'", + ) + payload = self._prepare_unmap_vol_from_host_grp_payload(host_group_id) + self.client.request( + constants.POST, + constants.UNMAP_VOLUME_FROM_HOST_URL.format(self.server_ip, volume_id), + payload, + ) + + def _prepare_unmap_vol_from_host_grp_payload(self, host_group_id): + unmap_vol_from_host_dict = {} + if host_group_id is not None: + unmap_vol_from_host_dict["host_group_id"] = host_group_id + + return unmap_vol_from_host_dict + + def get_volumes(self, filter_dict=None, all_pages=False): + """Get a list of volumes. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :return: Volume details + :rtype: list of dict + """ + LOG.info( + f"Getting volumes with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ID_AND_NAME, filter_dict, + ) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_VOLUME_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def get_volume_details(self, volume_id): + """Get details of a volume. + + :param volume_id: The volume ID + :type volume_id: str + :return: Volume details + :rtype: dict + """ + LOG.info( "Getting volume details by ID: '%s'", volume_id) + querystring = constants.SELECT_ALL_VOLUME + if helpers.is_victory_or_higher(): + querystring = constants.VICTORY_VOLUME_DETAILS_QUERY + elif helpers.is_foot_hill_prime_or_higher(): + querystring = constants.FHP_VOLUME_DETAILS_QUERY + elif helpers.is_foot_hill_or_higher(): + querystring = constants.FHC_VOLUME_DETAILS_QUERY + + resp = self.client.request( + constants.GET, + constants.GET_VOLUME_DETAILS_URL.format(self.server_ip, volume_id), + payload=None, + querystring=querystring, + ) + + hlu_details = self.get_host_volume_mapping(volume_id=volume_id) + + resp["hlu_details"] = hlu_details + + return resp + + def get_volume_by_name(self, volume_name): + """Get details of a volume by name. + + :param volume_name: The volume name + :type volume_name: str + :return: Volume details + :rtype: dict + """ + LOG.info( "Getting volume details by name: '%s'", volume_name) + querystring = constants.SELECT_ALL_VOLUME + if helpers.is_victory_or_higher(): + querystring = constants.VICTORY_VOLUME_DETAILS_QUERY + elif helpers.is_foot_hill_prime_or_higher(): + querystring = constants.FHP_VOLUME_DETAILS_QUERY + elif helpers.is_foot_hill_or_higher(): + querystring = constants.FHC_VOLUME_DETAILS_QUERY + + resp = self.client.request( + constants.GET, + constants.GET_VOLUME_BY_NAME_URL.format(self.server_ip), + payload=None, + querystring=helpers.prepare_querystring( + querystring, name=constants.EQUALS + volume_name, + ), + ) + + if resp: + LOG.info( "Getting host volume mapping from vol ID: '%s'", resp[0]['id']) + hlu_details = self.get_host_volume_mapping(volume_id=resp[0]["id"]) + resp[0]["hlu_details"] = hlu_details + + return resp + + def configure_metro_volume( + self, volume_id, remote_system_id, remote_appliance_id=None, + ): + """Configure the metro volume + :param volume_id: ID of the volume + :type volume_id: str + :param remote_system_id: ID of the remote system + :type remote_system_id: str + :param remote_appliance_id: ID of remote appliance to which volume will + be assigned + :type remote_appliance_id: str + :return: ID of metro session + :rtype: str + """ + LOG.info( + f"Configuring the metro volume {volume_id} to remote system {remote_system_id}", + ) + + if helpers.is_foot_hill_prime_or_higher(): + metro_url = constants.CONFIGURE_METRO_VOLUME + payload = {} + payload["remote_system_id"] = remote_system_id + if remote_appliance_id is not None: + payload["remote_appliance_id"] = remote_appliance_id + + return self.client.request( + constants.POST, + metro_url.format(self.server_ip, volume_id), + payload=payload, + ) + raise Exception("Not supported for PowerStore version less than 3.0.0.0") + + def end_volume_metro_config(self, volume_id, delete_remote_volume=None): + """End a metro configuration from a volume and keep both copies.The local + copy will retain its SCSI Identity while the remote volume will get a + new SCSI Identity + :param volume_id: ID of the volume + :type volume_id: str + :param delete_remote_volume: Whether to delete the remote volume during + the removal + :type delete_remote_volume: bool + :return: None if success else raise exception + :rtype: None + """ + LOG.info("End a metro configuration from a volume %s", volume_id) + if helpers.is_foot_hill_prime_or_higher(): + end_metro_url = constants.END_METRO_VOLUME + payload = {} + if delete_remote_volume is not None: + payload["delete_remote_volume"] = delete_remote_volume + + return self.client.request( + constants.POST, + end_metro_url.format(self.server_ip, volume_id), + payload=payload, + ) + raise Exception("Not supported for PowerStore version less than 3.0.0.0") + + def get_hosts(self, filter_dict=None, all_pages=False): + """Get a list of all the registered hosts. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :return: Hosts + :rtype: list of dict + """ + LOG.info( + f"Getting hosts with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ID_AND_NAME, filter_dict, + ) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_HOST_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def create_host( + self, name, os_type, initiators, description=None, host_connectivity=None, + ): + """Register a host on the array. + + :param name: The name of the host + :type name: str + :param os_type: The OS type of the host + :type os_type: str + :param initiators: Host initiators + :type initiators: list of dict + :param description: (optional) The description for the host + :type description: str + :param host_connectivity: (optional) Connectivity type for hosts + :type host_connectivity: str + :return: Host ID if success else raise exception + :rtype: dict + """ + LOG.info( + f"Creating host with name: '{name}' os_type: '{os_type}' initiators: '{initiators}'", + ) + payload = self._prepare_create_host_payload( + name, description, os_type, initiators, host_connectivity, + ) + return self.client.request( + constants.POST, constants.CREATE_HOST_URL.format(self.server_ip), payload, + ) + + def _prepare_create_host_payload( + self, name, description, os_type, initiators, host_connectivity, + ): + create_host_dict = {} + if name is not None: + create_host_dict["name"] = name + if description is not None: + create_host_dict["description"] = description + if os_type is not None: + create_host_dict["os_type"] = os_type + if initiators is not None: + create_host_dict["initiators"] = initiators + if host_connectivity is not None: + create_host_dict["host_connectivity"] = host_connectivity + + return create_host_dict + + def get_host_details(self, host_id): + """Get details of a particular host. + + :param host_id: The host ID + :type host_id: str + :return: Host details + :rtype: dict + """ + LOG.info( "Getting host details by ID: '%s'", host_id) + querystring = constants.SELECT_ALL_HOST + if helpers.is_foot_hill_prime_or_higher(): + querystring = constants.FHP_HOST_DETAILS_QUERY + elif helpers.is_foot_hill_or_higher(): + querystring = constants.FHC_HOST_DETAILS_QUERY + return self.client.request( + constants.GET, + constants.GET_HOST_DETAILS_URL.format(self.server_ip, host_id), + payload=None, + querystring=querystring, + ) + + def modify_host( + self, + host_id, + name=None, + description=None, + remove_initiators=None, + add_initiators=None, + modify_initiators=None, + host_connectivity=None, + ): + """Modify a given host - Only one of add, remove + or update in the same request. + + :param host_id: The host ID + :type host_id: str + :param name: (optional) The host name + :type name: str + :param description: (optional) The description for the host + :type description: str + :param remove_initiators: (optional) Initiators to be removed + :type remove_initiators: list + :param add_initiators: (optional) Initiators to be added + :type add_initiators: list + :param modify_initiators: (optional) Initiators to be modified + :type modify_initiators: list + :param host_connectivity: (optional)Connectivity types for hosts + :type host_connectivity: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Modifying host: '%s'", host_id) + payload = self._prepare_modify_host_payload( + name, + description, + remove_initiators, + add_initiators, + modify_initiators, + host_connectivity, + ) + return self.client.request( + constants.PATCH, + constants.MODIFY_HOST_URL.format(self.server_ip, host_id), + payload, + ) + + def _prepare_modify_host_payload( + self, + name=None, + description=None, + remove_initiators=None, + add_initiators=None, + modify_initiators=None, + host_connectivity=None, + ): + modify_host_dict = {} + if name is not None: + modify_host_dict["name"] = name + if description is not None: + modify_host_dict["description"] = description + if remove_initiators is not None: + modify_host_dict["remove_initiators"] = remove_initiators + elif add_initiators is not None: + modify_host_dict["add_initiators"] = add_initiators + elif modify_initiators is not None: + modify_host_dict["modify_initiators"] = modify_initiators + elif host_connectivity is not None: + modify_host_dict["host_connectivity"] = host_connectivity + + return modify_host_dict + + def add_initiators_to_host(self, host_id, add_initiators=None): + """Add initiators to host. + + :param host_id: The host ID. + :type host_id: str + :param add_initiators: (optional) Initiators to be added. + :type add_initiators: list + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Adding initiators to host: '%s'", host_id) + payload = self._prepare_modify_host_payload(add_initiators=add_initiators) + return self.client.request( + constants.PATCH, + constants.MODIFY_HOST_URL.format(self.server_ip, host_id), + payload, + ) + + def remove_initiators_from_host(self, host_id, remove_initiators=None): + """Remove initiators from Host. + + :param host_id: The host ID + :type host_id: str + :param remove_initiators: (optional) Initiators to be removed + :type remove_initiators: list + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Removing initiators to host: '%s'", host_id) + payload = self._prepare_modify_host_payload(remove_initiators=remove_initiators) + return self.client.request( + constants.PATCH, + constants.MODIFY_HOST_URL.format(self.server_ip, host_id), + payload, + ) + + def delete_host(self, host_id, force=None): + """Delete a host. + + :param host_id: The host ID. + :type host_id: str + :param force: (optional) The force_internal flag. + :type force: bool + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Deleting host: '%s'", host_id) + if force: + payload = {"force_internal": force} + else: + payload = None + return self.client.request( + constants.DELETE, + constants.DELETE_HOST_URL.format(self.server_ip, host_id), + payload, + ) + + def get_host_by_name(self, host_name): + """Get details of a Host with its name. + + :param host_name: The Host name. + :type host_name: str + :return: Host details + :rtype: dict + """ + LOG.info( "Getting host details by name: '%s'", host_name) + querystring = constants.SELECT_ALL_HOST + if helpers.is_foot_hill_prime_or_higher(): + querystring = constants.FHP_HOST_DETAILS_QUERY + elif helpers.is_foot_hill_or_higher(): + querystring = constants.FHC_HOST_DETAILS_QUERY + return self.client.request( + constants.GET, + constants.GET_HOST_BY_NAME_URL.format(self.server_ip), + payload=None, + querystring=helpers.prepare_querystring( + querystring, name=constants.EQUALS + host_name, + ), + ) + + def get_host_group_list(self, filter_dict=None, all_pages=False): + """Get a list of all host groups. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :return: Hosts + :rtype: list of dict + """ + LOG.info( + f"Getting hostgroup with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ID_AND_NAME, filter_dict, + ) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_HOST_GROUP_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def create_host_group(self, name, host_ids, description=None): + """Create a Host Group. + + :param name: The name of the host group + :type name: str + :param host_ids: Host IDs + :type host_ids: list + :param description: (optional) The description for the host group + :type description: str + :return: Host group ID if success else raise exception + :rtype: dict + """ + LOG.info( "Creating hostgroup: '%s' with host_ids: '%s'", name, host_ids) + payload = self._prepare_create_host_group_payload(name, host_ids, description) + return self.client.request( + constants.POST, + constants.CREATE_HOST_GROUP_URL.format(self.server_ip), + payload, + ) + + def _prepare_create_host_group_payload(self, name, host_ids, description): + create_host_group_dict = {} + if name is not None: + create_host_group_dict["name"] = name + if host_ids is not None: + create_host_group_dict["host_ids"] = host_ids + if description is not None: + create_host_group_dict["description"] = description + + return create_host_group_dict + + def get_host_group_details(self, host_group_id): + """Get details of a particular host group. + + :param host_group_id: The Host Group ID + :type host_group_id: str + :return: Host group details + :rtype: dict + """ + LOG.info( "Getting hostgroup details by ID: '%s'", host_group_id) + querystring = constants.SELECT_ALL_HOST_GROUP + if helpers.is_foot_hill_prime_or_higher(): + querystring = constants.FHP_HOST_GROUP_QUERY + + return self.client.request( + constants.GET, + constants.GET_HOST_GROUP_DETAILS_URL.format(self.server_ip, host_group_id), + payload=None, + querystring=querystring, + ) + + def get_host_group_by_name(self, host_group_name): + """Get details of a Host Group with its name. + + :param host_group_name: The Host Group name + :type host_group_name: str + :return: Host group details + :rtype: dict + """ + LOG.info( "Getting hostgroup details by name: '%s'", host_group_name) + querystring = constants.SELECT_ALL_HOST_GROUP + if helpers.is_foot_hill_prime_or_higher(): + querystring = constants.FHP_HOST_GROUP_QUERY + + return self.client.request( + constants.GET, + constants.GET_HOST_GROUP_BY_NAME_URL.format(self.server_ip), + payload=None, + querystring=helpers.prepare_querystring( + querystring, name=constants.EQUALS + host_group_name, + ), + ) + + def get_hosts_from_host_group(self, host_group_name): + """Get list of hosts which belong to Host Group. + + :param host_group_name: The Host Group name + :type host_group_name: str + :return: Hosts which are part of Host Group + :rtype: list + """ + LOG.info( "Getting hosts from host_group: '%s'", host_group_name) + return self.client.request( + constants.GET, + constants.GET_HOSTS_BY_HOST_GROUP.format(self.server_ip, host_group_name), + payload=None, + querystring=helpers.prepare_querystring( + name=constants.EQUALS + host_group_name, select="hosts(name,id)", + ), + ) + + def modify_host_group( + self, + host_group_id, + name=None, + remove_host_ids=None, + add_host_ids=None, + description=None, + host_connectivity=None, + ): + """Modify a Host group. + + :param host_group_id: The ID of the host group to be modified + :type host_group_id: str + :param name: (optional) The modified name of the host group + :type name: str + :param remove_host_ids: (optional) The hosts to be removed from + host group + :type remove_host_ids: list + :param add_host_ids: (optional) The hosts to be added to the host group + :type add_host_ids: list + :param description: (optional) The modified description for the + host group + :type description: str + :param host_connectivity: (Optional)Connectivity for host group + :type host_connectivity: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Modifying hostgroup: '%s'", host_group_id) + payload = self._prepare_modify_host_group_payload( + name, remove_host_ids, add_host_ids, description, host_connectivity, + ) + return self.client.request( + constants.PATCH, + constants.MODIFY_HOST_GROUP_URL.format(self.server_ip, host_group_id), + payload, + ) + + def _prepare_modify_host_group_payload( + self, + name=None, + remove_host_ids=None, + add_host_ids=None, + description=None, + host_connectivity=None, + ): + modify_host_group_dict = {} + if name is not None: + modify_host_group_dict["name"] = name + if description is not None: + modify_host_group_dict["description"] = description + if host_connectivity is not None: + modify_host_group_dict["host_connectivity"] = host_connectivity + + if remove_host_ids is not None: + modify_host_group_dict["remove_host_ids"] = remove_host_ids + elif add_host_ids is not None: + modify_host_group_dict["add_host_ids"] = add_host_ids + + return modify_host_group_dict + + def add_hosts_to_host_group(self, host_group_id, add_host_ids=None): + """Add Hosts to Host Group. + + :param host_group_id: The ID of the host group to be modified. + :type host_group_id: str + :param add_host_ids: (optional) The hosts to be added to the host group + :type add_host_ids: list + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Adding hosts to host_group: '%s'", host_group_id) + payload = self._prepare_modify_host_group_payload(add_host_ids=add_host_ids) + return self.client.request( + constants.PATCH, + constants.MODIFY_HOST_GROUP_URL.format(self.server_ip, host_group_id), + payload, + ) + + def remove_hosts_from_host_group(self, host_group_id, remove_host_ids=None): + """Remove Hosts from Host Group. + + :param host_group_id: The ID of the host group to be modified + :type host_group_id: str + :param remove_host_ids: (optional) Hosts to be removed from host group + :type remove_host_ids: list + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Removing hosts from host_group: '%s'", host_group_id) + payload = self._prepare_modify_host_group_payload( + remove_host_ids=remove_host_ids, + ) + return self.client.request( + constants.PATCH, + constants.MODIFY_HOST_GROUP_URL.format(self.server_ip, host_group_id), + payload, + ) + + def delete_host_group(self, host_group_id): + """Delete a host group. + + :param host_group_id: The ID of the host group + :type host_group_id: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Deleting hostgroup: '%s'", host_group_id) + return self.client.request( + constants.DELETE, + constants.DELETE_HOST_GROUP_URL.format(self.server_ip, host_group_id), + payload=None, + ) + + def get_volumes_from_volume_group(self, vol_group_name): + """Get a list of volumes which belong to Volume Group. + + :param vol_group_name: The Volume group name + :type vol_group_name: str + :return: Volumes which are part of Volume Group + :rtype: list + """ + LOG.info( "Getting volumes from volumegroup: %s", vol_group_name) + return self.client.request( + constants.GET, + constants.GET_VOLUMES_FROM_VOLUME_GROUP.format( + self.server_ip, vol_group_name, + ), + payload=None, + querystring=helpers.prepare_querystring( + name=constants.EQUALS + vol_group_name, select="volumes(name)", + ), + ) + + def get_volume_group_list(self, filter_dict=None, all_pages=False): + """Get a list of all the volume groups. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :return: Volume Groups + :rtype: list of dict + """ + LOG.info( + f"Getting volumegroups with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ID_AND_NAME, filter_dict, + ) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_VOLUME_GROUP_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def create_volume_group( + self, + name, + description=None, + volume_ids=None, + is_write_order_consistent=None, + protection_policy_id=None, + ): + """Create a volume group. + + :param name: The name of the volume group. + :type name: str + :param description: (optional) The description of the VG. + :type description: str + :param volume_ids: (optional) The volume IDs to be added to the VG + :type volume_ids: list + :param is_write_order_consistent: (optional) Indicate whether snapshot + sets of the volume group will be + write-order consistent. + :type is_write_order_consistent: vool + :param protection_policy_id: (optional) Unique identifier of a + protection policy to assign + to the volume group. + :type protection_policy_id: str + :return: Volume ID if success else raise exception + :rtype: dict + """ + LOG.info( "Creating volumegroup: '%s'", name) + payload = self._prepare_create_vg_payload( + name, + description, + volume_ids, + is_write_order_consistent, + protection_policy_id, + ) + return self.client.request( + constants.POST, + constants.CREATE_VOLUME_GROUP_URL.format(self.server_ip), + payload=payload, + ) + + def clone_volume_group( + self, volume_group_id, name, description=None, protection_policy_id=None, + ): + """Clone a volume group. + + :param volume_group_id: ID of the volume group to clone + :type volume_group_id: str + :param name: Unique name for the clone volume group. + :type name: str + :param description: (optional) Description for the clone volume group. + :type description: str + :param protection_policy_id: (optional) Unique identifier of the protection + policy to assign to the clone volume group + :type protection_policy_id: str + :return: Unique identifier of the new instance created if success else raise exception + :rtype: dict + """ + LOG.info( "Cloning volumegroup: '%s'", volume_group_id) + payload = self._prepare_clone_vg_payload( + name, description, protection_policy_id, + ) + return self.client.request( + constants.POST, + constants.CLONE_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), + payload=payload, + ) + + def refresh_volume_group( + self, + volume_group_id, + src_vol_group, + create_backup_snap=None, + backup_snap_profile=None, + ): + """Refresh a volume group. + + :param volume_group_id: ID of the volume group to refresh + :type volume_group_id: str + :param src_vol_group: Unique identifier of the volume group to refresh from. + :type src_vol_group: str + :param create_backup_snap: (optional) specifies whether a backup snapshot set of the + target volume group needs to be created before refreshing it. + :type create_backup_snap: bool + :param backup_snap_profile: (optional) Backup profile of the snapshot set to be created. + :type backup_snap_profile: dict + :return: Unique identifier of the backup snapshot set or None if create_backup_snap is None + if success else raise exception + :rtype: dict + """ + LOG.info( "Refreshing volumegroup: '%s'", volume_group_id) + payload = self._prepare_vg_payload( + "refresh", src_vol_group, create_backup_snap, backup_snap_profile, + ) + return self.client.request( + constants.POST, + constants.REFRESH_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), + payload=payload, + ) + + def restore_volume_group( + self, + volume_group_id, + src_snap_id, + create_backup_snap=None, + backup_snap_profile=None, + ): + """Restore a volume group. + + :param volume_group_id: ID of the volume group to restore + :type volume_group_id: str + :param src_snap_id: Unique identifier of the snapshot set to restore from. + :type src_snap_id: str + :param create_backup_snap: (optional) specifies whether a backup snapshot set of the + target volume group needs to be created before restore. + :type create_backup_snap: bool + :param backup_snap_profile: (optional) Backup profile of the snapshot set to be created. + :type backup_snap_profile: dict + :return: Unique identifier of the backup snapshot set or None if create_backup_snap is None + if success else raise exception + :rtype: dict + """ + LOG.info( "Restoring volumegroup: '%s'", volume_group_id) + payload = self._prepare_vg_payload( + "restore", src_snap_id, create_backup_snap, backup_snap_profile, + ) + return self.client.request( + constants.POST, + constants.RESTORE_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), + payload=payload, + ) + + def _prepare_clone_vg_payload(self, name, description, protection_policy_id): + vol_group_clone = {} + if name is not None: + vol_group_clone["name"] = name + if description is not None: + vol_group_clone["description"] = description + if protection_policy_id is not None: + vol_group_clone["protection_policy_id"] = protection_policy_id + return vol_group_clone + + def _prepare_vg_payload( + self, action, src_vol_group, create_backup_snap, backup_snap_profile, + ): + vg_payload = {} + if action == "refresh": + vg_payload["from_object_id"] = src_vol_group + else: + vg_payload["from_snap_id"] = src_vol_group + if create_backup_snap is not None: + vg_payload["create_backup_snap"] = create_backup_snap + if backup_snap_profile: + vg_payload["backup_snap_profile"] = backup_snap_profile + + return vg_payload + + def _prepare_create_vg_payload( + self, + name, + description, + volume_ids, + is_write_order_consistent, + protection_policy_id, + ): + create_volume_group_dict = {} + if name is not None: + create_volume_group_dict["name"] = name + if description is not None: + create_volume_group_dict["description"] = description + if volume_ids is not None: + create_volume_group_dict["volume_ids"] = volume_ids + if is_write_order_consistent is not None: + create_volume_group_dict["is_write_order_consistent"] = ( + is_write_order_consistent + ) + if protection_policy_id is not None: + create_volume_group_dict["protection_policy_id"] = protection_policy_id + + return create_volume_group_dict + + def get_volume_group_details(self, volume_group_id): + """Get details of a volume group. + + :param volume_group_id: The volume group ID + :type volume_group_id: str + :return: Details of the volume group + :rtype: dict + """ + LOG.info( "Getting volumegroup details by ID: '%s'", volume_group_id) + return self.client.request( + constants.GET, + constants.GET_VOLUME_GROUP_DETAILS_URL.format( + self.server_ip, volume_group_id, + ), + payload=None, + querystring=helpers.prepare_querystring(constants.SELECT_ALL_VOL_GROUP), + ) + + def get_volume_group_by_name(self, volume_group_name): + """Get details of a volume group by name. + + :param volume_group_name: The name of the volume group + :type volume_group_name: str + :return: Details of the volume group + :rtype: dict + """ + LOG.info( "Getting volumegroup details by name: '%s'", volume_group_name) + return self.client.request( + constants.GET, + constants.GET_VOLUME_GROUP_BY_NAME_URL.format(self.server_ip), + payload=None, + querystring=helpers.prepare_querystring( + constants.SELECT_ALL_VOL_GROUP, + name=constants.EQUALS + volume_group_name, + ), + ) + + def modify_volume_group( + self, + volume_group_id, + name=None, + description=None, + is_write_order_consistent=None, + protection_policy_id=None, + ): + """Modify a volume group. + + :param volume_group_id: The id of the volume group + :type volume_group_id: str + :param name: (optional) The name of the volume group + :type name: str + :param description: (optional) The description of the VG + :type description: str + :param is_write_order_consistent: (optional) Indicate whether snapshot + sets of the volume group will be + write-order consistent. + :type is_write_order_consistent: bool + :param protection_policy_id: (optional) Unique identifier of the + protection policy to assign to a primary + or clone volume group. If an empty string + is specified, protection policy will be + removed from the volume group. + :type protection_policy_id: str + """ + LOG.info( "Modifying volumegroup: '%s'", volume_group_id) + payload = self._prepare_modify_vg_payload( + name, description, is_write_order_consistent, protection_policy_id, + ) + self.client.request( + constants.PATCH, + constants.MODIFY_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), + payload, + ) + + def _prepare_modify_vg_payload( + self, name, description, is_write_order_consistent, protection_policy_id, + ): + modify_vg_dict = {} + if name is not None: + modify_vg_dict["name"] = name + if description is not None: + modify_vg_dict["description"] = description + if is_write_order_consistent is not None: + modify_vg_dict["is_write_order_consistent"] = is_write_order_consistent + if protection_policy_id is not None: + modify_vg_dict["protection_policy_id"] = protection_policy_id + + return modify_vg_dict + + def delete_volume_group(self, volume_group_id): + """Delete a volume group. + + :param: volume_group_id: The volume group ID + :type: volume_group_id: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Deleting volumegroup: '%s'", volume_group_id) + return self.client.request( + constants.DELETE, + constants.DELETE_VOLUME_GROUP_URL.format(self.server_ip, volume_group_id), + payload=None, + ) + + def add_members_to_volume_group( + self, volume_group_id, volume_ids, force_internal=False, + ): + """Add members to volume group. + + :param volume_ids: The volume IDs to be added + :type volume_ids: list + :param force_internal: (optional) The force internal flag + :type force_internal: bool + :return: None if success else raise exception + :rtype: None + """ + LOG.info( + f"Adding volumes: '{volume_ids}' to volumegroup: '{volume_group_id}'", + ) + payload = self._prepare_add_members_to_volume_group_payload( + volume_ids, force_internal, + ) + return self.client.request( + constants.POST, + constants.ADD_MEMBERS_TO_VOLUME_GROUP_URL.format( + self.server_ip, volume_group_id, + ), + payload=payload, + ) + + def _prepare_add_members_to_volume_group_payload(self, volume_ids, force_internal): + add_members_to_vg_dict = {} + if volume_ids is not None: + add_members_to_vg_dict["volume_ids"] = volume_ids + if force_internal is not None: + add_members_to_vg_dict["force_internal"] = force_internal + + return add_members_to_vg_dict + + def remove_members_from_volume_group( + self, volume_group_id, volume_ids, force_internal=False, + ): + """Remove members from volume group. + + :param volume_ids: The list of volume IDs to be removed + :type volume_ids: str + :param force_internal: (optional) The force internal flag + :type force_internal: bool + :return: None if success else raise exception + :rtype: None + :rtype None or dict + """ + LOG.info( + f"Removing volumes: '{volume_ids}' from volumegroup: '{volume_group_id}'", + ) + payload = self._prepare_remove_members_from_volume_group_payload( + volume_ids, force_internal, + ) + return self.client.request( + constants.POST, + constants.REMOVE_MEMBERS_FROM_VOLUME_GROUP_URL.format( + self.server_ip, volume_group_id, + ), + payload=payload, + ) + + def _prepare_remove_members_from_volume_group_payload( + self, volume_ids, force_internal, + ): + remove_members_from_vg_dict = {} + if volume_ids is not None: + remove_members_from_vg_dict["volume_ids"] = volume_ids + if force_internal is not None: + remove_members_from_vg_dict["force_internal"] = force_internal + + return remove_members_from_vg_dict + + def get_nodes(self, filter_dict=None, all_pages=False): + """Returns a list of nodes. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :return: Nodes + :rtype: list of dict + """ + LOG.info( + f"Getting nodes with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ID_AND_NAME, filter_dict, + ) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_NODE.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def get_cluster_list(self): + """Returns a list of clusters. + + :return: Clusters + :rtype: list of dict + """ + LOG.info("Getting clusters") + return self.client.request( + constants.GET, + constants.GET_CLUSTER.format(self.server_ip), + payload=None, + querystring=constants.CLUSTER_DETAILS_QUERY, + ) + + def get_host_volume_mapping(self, volume_id): + """Get Host volume mapping details. + + :param volume_id: The Volume ID + :type volume_id: str + :return: Host volume mapping details + :rtype: dict + """ + LOG.info( "Getting host mapping with vol: '%s'", volume_id) + return self.client.request( + constants.GET, + constants.HOST_VOLUME_MAPPING_URL.format(self.server_ip), + payload=None, + querystring=helpers.prepare_querystring( + constants.SELECT_ALL_HOST_VOLUME_MAPPING, + volume_id=constants.EQUALS + volume_id, + ), + ) + + # NAS Server methods + + def get_nas_servers(self, filter_dict=None, all_pages=False): + """Get a list of nas servers. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :return: NAS servers + :rtype: list of dict + """ + LOG.info( + f"Getting nasservers with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ID_AND_NAME, filter_dict, + ) + LOG.info( "Querystring: %s", querystring) + return self.client.request( + constants.GET, + constants.GET_NAS_SERVER_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def get_nas_server_details(self, nas_server_id): + """Details of a Nas Server. + + :param nas_server_id: The NAS Server ID + :type nas_server_id: str + :return: NAS server details + :rtype: dict + """ + querystring = constants.SELECT_ALL_NAS_SERVER + if helpers.is_foot_hill_prime_or_higher(): + querystring = constants.FHP_NAS_QUERYSTRING + + LOG.info( "Getting nasserver details by ID: '%s'", nas_server_id) + return self.client.request( + constants.GET, + constants.GET_NAS_SERVER_DETAILS_URL.format(self.server_ip, nas_server_id), + payload=None, + querystring=querystring, + ) + + def get_nas_server_by_name(self, nas_server_name): + """Get details of a NAS Server by name. + + :param nas_server_name: The name of the NAS Server + :type nas_server_name: str + :return: NAS server details + :rtype: dict + """ + querystring = constants.SELECT_ALL_NAS_SERVER + if helpers.is_foot_hill_prime_or_higher(): + querystring = constants.FHP_NAS_QUERYSTRING + + LOG.info( "Getting nasserver details by name: '%s'", nas_server_name) + return self.client.request( + constants.GET, + constants.GET_NAS_SERVER_DETAILS_BY_NAME_URL.format(self.server_ip), + payload=None, + querystring=helpers.prepare_querystring( + querystring, name=constants.EQUALS + nas_server_name, + ), + ) + + def create_nasserver(self, payload): + """Create a NAS Server. + + :param payload: The payload to create the NAS Server + :type payload: dict + :return: NAS server ID on success else raise exception + :rtype: dict + """ + LOG.info( "Creating NAS server: '%s'", payload.get('name')) + if ( + "protection-policy" in payload + and not helpers.is_foot_hill_prime_or_higher() + ): + raise Exception( + "Protection policy is supported for PowerStore" + " version 3.0.0.0 and above.", + ) + return self.client.request( + constants.POST, + constants.CREATE_NAS_SERVER_URL.format(self.server_ip), + payload=payload, + ) + + def modify_nasserver(self, nasserver_id, modify_parameters): + """Modify NAS Server attributes. + + :param nasserver_id: The ID of the NAS Server + :type nasserver_id: str + :param modify_parameters: Attributes to be modified + :type modify_parameters: dict + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Modifying nasserver: '%s'", nasserver_id) + if modify_parameters: + payload = {} + for key, value in modify_parameters.items(): + if value is not None: + payload[key] = value + + if payload: + return self.client.request( + constants.PATCH, + constants.MODIFY_NAS_SERVER_URL.format( + self.server_ip, nasserver_id, + ), + payload=payload, + ) + + raise ValueError("Nothing to modify") + + def delete_nasserver(self, nasserver_id): + """Delete a NAS Server. + + :param nasserver_id: The ID of the NAS Server to delete + :type nasserver_id: str + :return: None on success else raise exception + :rtype: None + """ + LOG.info( "Deleting NAS server: '%s'", nasserver_id) + return self.client.request( + constants.DELETE, + constants.DELETE_NAS_SERVER_URL.format(self.server_ip, nasserver_id), + ) + + # NAS Server methods end + + # File System Methods + def get_file_systems(self, filter_dict=None, all_pages=False): + """Get a list of file systems. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + + :returns: File systems + :rtype: list of dict + """ + LOG.info( + f"Getting filesystems with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ID_AND_NAME, filter_dict, + ) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_FILE_SYSTEM_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def get_filesystem_details(self, filesystem_id): + """Details of a Filesystem. + + :param filesystem_id: The File System ID + :type filesystem_id: str + :returns: File system details + :rtype: dict + """ + LOG.info( "Getting filesystem details by ID: '%s'", filesystem_id) + querystring = constants.SELECT_ALL_FILESYSTEM + if helpers.is_foot_hill_prime_or_higher(): + querystring = constants.SELECT_ALL_FILESYSTEM_PRIME + return self.client.request( + constants.GET, + constants.GET_FILESYSTEM_DETAILS_URL.format(self.server_ip, filesystem_id), + payload=None, + querystring=querystring, + ) + + def get_filesystem_by_name(self, filesystem_name, nas_server_id): + """Get details of a filesystem by name. + + :param filesystem_name: The name of the File System + :type filesystem_name: str + :returns: File system details + :rtype: dict + """ + LOG.info( + "Getting filesystem details by name: '%s' and NAS Server: " + "'%s'" , filesystem_name, nas_server_id, + ) + querystring = constants.SELECT_ALL_FILESYSTEM + if helpers.is_foot_hill_prime_or_higher(): + querystring = constants.SELECT_ALL_FILESYSTEM_PRIME + return self.client.request( + constants.GET, + constants.GET_FILESYSTEM_DETAILS_BY_NAME_URL.format(self.server_ip), + payload=None, + querystring=helpers.prepare_querystring( + querystring, + nas_server_id=constants.EQUALS + nas_server_id, + name=constants.EQUALS + filesystem_name, + ), + ) + + def create_filesystem(self, name, nas_server_id, size_total, advance_parameters): + """Create a filesystem. + + :param name: The name of the File System + :type name: str + :param nas_server_id: The ID of the NAS Server + :type name: str + :param size_total: Total size of the file system in bytes + :type name: str + :param advance_parameters: Advance attributes + :type advance_parameters: str + :return: Filesystem ID on success else raise exception + :rtype: dict + """ + LOG.info( "Creating filesystem: '%s'", name) + payload = {} + payload["name"] = name + payload["nas_server_id"] = nas_server_id + payload["size_total"] = size_total + + if advance_parameters: + for key, value in advance_parameters.items(): + if ( + key in constants.FILESYSTEM_PRIME + and not helpers.is_foot_hill_prime_or_higher() + ): + raise Exception( + key + " is supported for PowerStore version 3.0.0.0 and above.", + ) + payload[key] = value + return self.client.request( + constants.POST, + constants.CREATE_FILESYSTEM_URL.format(self.server_ip), + payload=payload, + ) + + def delete_filesystem(self, filesystem_id): + """Delete a File System. + + :param filesystem_id: The FileSystem ID + :type filesystem_id: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Deleting filesystem: '%s'", filesystem_id) + return self.client.request( + constants.DELETE, + constants.DELETE_FILESYSTEM_URL.format(self.server_ip, filesystem_id), + payload=None, + ) + + def get_snapshots_filesystem(self, filesystem_id): + """Get Snapshots of a Filesystem. + + :param filesystem_id: The File System ID + :type filesystem_id: str + :returns: Snapshots of a FileSystem + :rtype: list + """ + LOG.info( "Getting snapshots of filesystem: '%s'", filesystem_id) + return self.client.request( + constants.GET, + constants.GET_SNAPSHOTS_FILESYSTEM_URL.format(self.server_ip), + querystring=helpers.prepare_querystring( + constants.SELECT_ID_AND_NAME, parent_id=constants.EQUALS + filesystem_id, + ), + ) + + def modify_filesystem(self, filesystem_id, modify_parameters): + """Modify FileSystem attributes. + :param filesystem_id: The ID of the FileSystem + :type filesystem_id: str + :param modify_parameters: Attributes to be modified + :type modify_parameters: dict + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Modifying filesystem: '%s'", filesystem_id) + if modify_parameters: + payload = {} + for key, value in modify_parameters.items(): + if ( + key in constants.FILESYSTEM_PRIME + and not helpers.is_foot_hill_prime_or_higher() + ): + raise Exception( + key + " is supported for PowerStore version 3.0.0.0 and above.", + ) + if value is not None: + payload[key] = value + + if payload: + return self.client.request( + constants.PATCH, + constants.MODIFY_FILESYSTEM_URL.format( + self.server_ip, filesystem_id, + ), + payload=payload, + ) + + raise ValueError("Nothing to modify") + + # File System methods end + + # NFS Export Methods + def get_nfs_exports(self, filter_dict=None, all_pages=False): + """Get a list of nfs exports. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :returns: NFS exports + :rtype: list of dict + """ + LOG.info( + f"Getting nfsexports with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ID_AND_NAME, filter_dict, + ) + LOG.info( "Querystring: %s", querystring) + return self.client.request( + constants.GET, + constants.GET_NFS_EXPORT_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def get_nfs_export_details(self, nfs_export_id): + """Get details of a particular NFS Export. + + :param nfs_export_id: The ID of the NFS Export + :type nfs_export_id: str + :returns: NFS Export details + :rtype: dict + """ + LOG.info( "Getting nfsexport details by ID: '%s'", nfs_export_id) + return self.client.request( + constants.GET, + constants.GET_NFS_EXPORT_DETAILS_URL.format(self.server_ip, nfs_export_id), + querystring=constants.SELECT_ALL_NFS_EXPORT, + ) + + def get_nfs_export_details_by_name(self, nfs_export_name): + """Get details of a NFS Export by name. + + :param nfs_export_name: The name of the NFS Export + :type nfs_export_name: str + :returns: NFS Export details + :rtype: list + """ + LOG.info( "Getting nfsexport details by name: '%s'", nfs_export_name) + return self.client.request( + constants.GET, + constants.GET_NFS_EXPORT_DETAILS_BY_NAME_URL.format(self.server_ip), + querystring=helpers.prepare_querystring( + constants.SELECT_ALL_NFS_EXPORT, name=constants.EQUALS + nfs_export_name, + ), + ) + + def create_nfs_export(self, file_system_id, path, name, nfs_other_params): + """Create NFS Export of filesystem. + + :param file_system_id: The ID of the filesystem on which NFS Export + will be created + :type file_system_id: str + :param path: Local path to export relative to the NAS server root + :type path: str + :param name: The name of the NFS Export + :type name: str + :param nfs_other_params: Dictionary containing attributes with + which NFS Export will be created + :type nfs_other_params: dict + :returns: The ID of the NFS export + :rtype: dict + """ + LOG.info( "Creating NFSExport: '%s'", name) + payload = {} + payload["name"] = name + payload["file_system_id"] = file_system_id + payload["path"] = path + if nfs_other_params: + payload.update(nfs_other_params) + return self.client.request( + constants.POST, + constants.CREATE_NFS_EXPORT_URL.format(self.server_ip), + payload=payload, + ) + + def modify_nfs_export(self, nfs_export_id, nfs_other_params): + """Modify NFS Export attributes. + + :param nfs_export_id: The ID of the NFS Export + :type nfs_export_id: str + :param nfs_other_params: Dictionary containing attributes to be + modified of the NFS Export + :type nfs_other_params: dict + :return: None if success else raise exception + :rtype: None + """ + LOG.info( + f"Modifying nfsexport: '{nfs_export_id}' with params: '{nfs_other_params}'", + ) + return self.client.request( + constants.PATCH, + constants.MODIFY_NFS_EXPORT_URL.format(self.server_ip, nfs_export_id), + payload=nfs_other_params, + ) + + def delete_nfs_export(self, nfs_export_id): + """Delete NFS Export. + + :param nfs_export_id: The ID of the NFS Export + :type nfs_export_id: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Deleting nfsexport: '%s'", nfs_export_id) + return self.client.request( + constants.DELETE, + constants.DELETE_NFS_EXPORT_URL.format(self.server_ip, nfs_export_id), + ) + + # NFS Export Method ENDs + + # SMB Share Methods + def get_smb_shares(self, filter_dict=None, all_pages=False): + """Get a list of smb shares. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + + :returns: SMB shares + :rtype: list of dict + """ + LOG.info( + f"Getting smbshares with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ALL_SMB_SHARE, filter_dict, + ) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_SMB_SHARE_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def get_smb_share_by_name(self, share_name): + """Get details of a SMB Share with its name. + + :param share_name: The name of the smb share. + :type share_name: str + :return: SMB share details + :rtype: dict + """ + LOG.info( "Getting smbshare details by name: '%s'", share_name) + return self.client.request( + constants.GET, + constants.GET_SMB_SHARE_LIST_URL.format(self.server_ip), + querystring=helpers.prepare_querystring( + constants.SELECT_ALL_SMB_SHARE, name=constants.EQUALS + share_name, + ), + ) + + def get_smb_share(self, share_id): + """Get details of a SMB Share with its id. + + :param share_id: The Id of the SMB share. + :type share_id: str + :return: SMB share details + :rtype: dict + """ + LOG.info( "Getting smbshare details by ID: '%s'", share_id) + return self.client.request( + constants.GET, + constants.GET_SMB_SHARE_DETAILS_URL.format(self.server_ip, share_id), + querystring=constants.SELECT_ALL_SMB_SHARE, + ) + + def create_smb_share(self, file_system_id, path, name, **kw_smb_other_params): + """Create SMB share + + :param file_system_id: The ID of the File System. + :type file_system_id: str + :param path: Local path to the file system or any existing sub-folder + of the file system that is shared over the network. + :type path: str + :param name: Name of the SMB Share. + :type name: str + :param kw_smb_other_params: Advance parameters. + :type name: dict + :return: The ID of the smb share if successful else error. + :rtype: dict + """ + LOG.info( "Creating smbshare: '%s'", name) + payload = {} + payload["name"] = name + payload["file_system_id"] = file_system_id + payload["path"] = path + if kw_smb_other_params: + for key, value in kw_smb_other_params.items(): + payload[key] = value + return self.client.request( + constants.POST, + constants.CREATE_SMB_SHARE_URL.format(self.server_ip), + payload=payload, + ) + + def update_smb_share(self, id, **kw_smb_other_params): + """Modify a SMB Share. + + :param id: The ID of SMB Share. + :param kw_smb_other_params: Parameters which are to be modified. + :return: None if success else raise exception + :rtype: None + """ + LOG.info( + f"Modifying smbshare: '{id}' with params: '{kw_smb_other_params}'", + ) + return self.client.request( + constants.PATCH, + constants.MODIFY_SMB_SHARE_URL.format(self.server_ip, id), + payload=kw_smb_other_params, + ) + + def delete_smb_share(self, share_id): + """Delete a SMB Share. + + :param share_id: The ID of the SMB share. + :type share_id: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Deleting smbshare: '%s'", share_id) + return self.client.request( + constants.DELETE, + constants.DELETE_SMB_SHARE_URL.format(self.server_ip, share_id), + ) + + # SMB Share Methods End + + # ACL Methods + + def get_acl(self, share_id): + """Retrieves the Access Control List (ACL) details for a given share ID. + + :param share_id: The ID of the share for which to retrieve the ACL details. + :type share_id: str + :return: The response from the client's request to retrieve the ACL details. + :rtype: dict + """ + LOG.info( "Getting ACL details: '%s'", share_id) + return self.client.request( + constants.POST, + constants.GET_ACL_DETAILS.format(self.server_ip, share_id), + ) + + def set_acl(self, share_id, add_aces=None, remove_aces=None): + """Sets the access control list (ACL) for a given share. + + Args: + share_id (str): The ID of the share. + add_aces (list, optional): A list of access control entries + (ACEs) to add to the ACL. Defaults to None. + remove_aces (list, optional): A list of access control entries + (ACEs) to remove from the ACL. Defaults to None. + + Returns: + dict: The response from the server after setting the ACL. + + """ + payload = {} + if add_aces: + payload["add_aces"] = add_aces + if remove_aces: + payload["remove_aces"] = remove_aces + return self.client.request( + constants.POST, + constants.SET_ACL_DETAILS.format(self.server_ip, share_id), + payload=payload, + ) + + # ACL Methods End + + # FS Quota Methods + def get_file_tree_quotas(self, filter_dict=None, all_pages=False): + """Get a list of file tree quotas. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :returns: File tree quotas + :rtype: list of dict + """ + LOG.info( + f"Getting tree quotas with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring( + constants.SELECT_ID_AND_PATH, filter_dict, + ) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_TREE_QUOTA_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def get_file_user_quotas(self, filter_dict=None, all_pages=False): + """Get a list of file user quotas. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :returns: File user quotas + :rtype: list of dict + """ + LOG.info( + f"Getting user quotas with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring(filter_dict) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_USER_QUOTA_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + def get_tree_quota(self, tree_quota_id, path=None, file_system_id=None): + """Get details of Tree Quota either by its ID or + by path and the filesystem_id. + + :param tree_quota_id: The Id of the Tree Quota. + :type tree_quota_id: str + :param path: (optional) Path of the tree relative to the root of the + associated filesystem. + :type path: str + :param file_system_id: (optional) ID of the associated filesystem. + :type file_system_id: str + :return: Tree quota details + :rtype: dict + """ + if tree_quota_id: + LOG.info( "Getting tree quota details by ID: '%s'", tree_quota_id) + return self.client.request( + constants.GET, + constants.GET_TREE_QUOTA_DETAILS_URL.format( + self.server_ip, tree_quota_id, + ), + querystring=constants.SELECT_ALL_TREE_QUOTA, + ) + LOG.info( + f"Getting tree quota details by path: '{tree_quota_id}' and fs_id: '{file_system_id}'", + ) + return self.client.request( + constants.GET, + constants.GET_TREE_QUOTA_LIST_URL.format(self.server_ip), + querystring=helpers.prepare_querystring( + constants.SELECT_ALL_TREE_QUOTA, + path=constants.EQUALS + path, + file_system_id=constants.EQUALS + file_system_id, + ), + ) + + def get_user_quota(self, user_quota_id, query_params=None): + """Get details of User Quota with its id or by other user quota + parameters. + + :param user_quota_id: The Id of the User Quota. + :type user_quota_id: str + :param query_params: (optional) Other parameters of User Quota + :type query_params: dict + :return: User Quota details + :rtype: dict + """ + if user_quota_id: + LOG.info( "Getting user quota details by ID: '%s'", user_quota_id) + return self.client.request( + constants.GET, + constants.GET_USER_QUOTA_DETAILS_URL.format( + self.server_ip, user_quota_id, + ), + querystring=constants.SELECT_ALL_USER_QUOTA, + ) + if query_params: + for key, value in query_params.items(): + query_params[key] = constants.EQUALS + value + LOG.info( "Getting user quota details by params: '%s'", query_params) + return self.client.request( + constants.GET, + constants.GET_USER_QUOTA_LIST_URL.format(self.server_ip), + querystring=helpers.prepare_querystring( + constants.SELECT_ALL_USER_QUOTA, query_params, + ), + ) + + def create_tree_quota(self, file_system_id, path, tree_quota_params): + """Create a Tree Quota. + + :param file_system_id: The ID of the File System. + :type file_system_id: str + :param path: Path relative to the root of the associated filesystem. + :type path: str + :param tree_quota_params: Remaining Tree Quota parameters. + :type tree_quota_params: dict + :return: The ID of the Tree Quota if successful else error. + :rtype: dict + """ + LOG.info( "Creating tree quota on filesystem ID: '%s'", file_system_id) + payload = {} + payload["file_system_id"] = file_system_id + payload["path"] = path + if tree_quota_params: + payload.update(tree_quota_params) + return self.client.request( + constants.POST, + constants.CREATE_TREE_QUOTA_URL.format(self.server_ip), + payload=payload, + ) + + def create_user_quota(self, file_system_id, user_quota_params): + """Create a User Quota. + + :param file_system_id: The ID of the File System. + :type file_system_id: str + :param user_quota_params: Remaining User Quota parameters. + :type user_quota_params: dict + :return: The ID of the User Quota if successful else error. + :rtype: dict + """ + LOG.info( "Creating user quota on filesystem ID: '%s'", file_system_id) + payload = {} + payload["file_system_id"] = file_system_id + if user_quota_params: + payload.update(user_quota_params) + return self.client.request( + constants.POST, + constants.CREATE_USER_QUOTA_URL.format(self.server_ip), + payload=payload, + ) + + def update_tree_quota(self, tree_quota_id, tree_quota_params): + """Update a Tree Quota. + + :param tree_quota_id: The ID of Tree Quota. + :type tree_quota_id: str + :param tree_quota_params: Tree Quota parameters to be modified. + :type tree_quota_params: dict + :return: None if success else raise exception + :rtype: None + """ + LOG.info( + f"Modifying tree quota: '{tree_quota_id}' with params: '{tree_quota_params}'", + ) + return self.client.request( + constants.PATCH, + constants.MODIFY_TREE_QUOTA_URL.format(self.server_ip, tree_quota_id), + payload=tree_quota_params, + ) + + def update_user_quota(self, user_quota_id, user_quota_params): + """Update a User Quota. + + :param user_quota_id: The ID of User Quota. + :type user_quota_id: str + :param user_quota_params: User Quota parameters to be modified. + :type user_quota_params: dict + :return: None if success else raise exception + :rtype: None + """ + LOG.info( + f"Modifying user quota: '{user_quota_id}' with params: '{user_quota_params}'", + ) + return self.client.request( + constants.PATCH, + constants.MODIFY_USER_QUOTA_URL.format(self.server_ip, user_quota_id), + payload=user_quota_params, + ) + + def delete_tree_quota(self, tree_quota_id): + """Delete a Tree Quota. + :param tree_quota_id: The ID of the Tree Quota. + :type tree_quota_id: str + :return: None if success else raise exception + :rtype: None + """ + LOG.info( "Deleting tree quota: '%s'", tree_quota_id) + return self.client.request( + constants.DELETE, + constants.DELETE_TREE_QUOTA_URL.format(self.server_ip, tree_quota_id), + ) + + # FS Quota Methods end + + # Job Methods start + + def get_job_details(self, job_id): + """Get details of a Job with its id. + :param job_id: The Id of job. + :type job_id: str + :return: Job details + :rtype: dict + """ + LOG.info( "Getting job details: '%s'", job_id) + querystring = constants.JOB_DETAILS_QUERY + if helpers.is_foot_hill_or_higher(): + querystring = constants.FHC_JOB_DETAILS_QUERY + return self.client.request( + constants.GET, + constants.GET_JOB_DETAILS_URL.format(self.server_ip, job_id), + querystring=querystring, + ) + + # Job Methods end + + # AD methods start + + def get_file_ads(self, filter_dict=None, all_pages=False): + """Get a list of active directories. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :returns: active directories + :rtype: list of dict + """ + LOG.info( + f"Getting active directories with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring(filter_dict) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_AD_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + # AD Methods end + + # LDAP method start + + def get_file_ldaps(self, filter_dict=None, all_pages=False): + """Get a list of ldap. + + :param filter_dict: (optional) Filter detail + :type filter_dict: dict + :param all_pages: (optional) Indicates whether to return all element + or not + :type all_pages: bool + :returns: ldap + :rtype: list of dict + """ + LOG.info( + f"Getting ldap with filter: '{filter_dict}' and all_pages: {all_pages}", + ) + querystring = helpers.prepare_querystring(filter_dict) + LOG.info( "Querystring: '%s'", querystring) + return self.client.request( + constants.GET, + constants.GET_LDAP_LIST_URL.format(self.server_ip), + payload=None, + querystring=querystring, + all_pages=all_pages, + ) + + # LDAP method end