Module cvpysdk.storage_pool

File for doing operations on an Storage Pools.

This module has classes defined for doing operations for Storage Pools:

StoragePools, StoragePoolType, StorageType, WORMLockType and StoragePool are the classes defined in this file.

StoragePools: Class for representing all the StoragePools in the commcell

StoragePoolType : Class for representing storage pool types like deduplication, secondary copy, non-dedupe, scale out

StorageType : Class for representing storage types like disk, cloud, tape of a storage pool

WORMLockType : Class for representing different WORM lock types flag values of a WORM enable storage pool

StoragePool: Class for representing a single StoragePool of the commcell

StoragePools

__init__(commcell_object)   --  initializes object of the StoragePools class associated with the commcell

__str__()                   --  returns all the storage pools associated with the commcell

__repr__()                  --  returns the string representation of an instance of this class

__len__()                   --  returns the number of storage pools added to the Commcell

__getitem__()               --  returns the name of the storage pool for the given storage
pool Id or the details for the given storage pool name

_get_storage_pools()        --  returns all storage pools added to the commcell

has_storage_pool()          --  checks whether the storage pool  with given name exists or not

get()                       --  returns StoragePool object of the storage pool for the
                                specified input name

add()                       --  Adds a storage pool, according to given input and returns
                                StoragePool object

delete()                    --  deletes the specified storage pool

refresh()                   --  refresh the list of storage pools associated with the commcell

add_air_gap_protect()       --  Adds a new air gap protect storage pool to commcell

Attributes

**all_storage_pools**   --  returns dict of all the storage pools on commcell
StoragePool
 

===========

__init__()                  --  initialize the instance of StoragePool class for specific storage pool of commcell

__repr__()                  --  returns a string representation of the StoragePool instance

 _get_storage_pool_properties() --  returns the properties of this storage pool

refresh()                   --      Refresh the properties of the StoragePool

get_copy()                  --  Returns the StoragePolicyCopy object of Storage Pool copy

enable_compliance_lock()    --  Enables compliance lock on Storage Pool Copy

enable_worm_storage_lock()  --  Enables WORM storage lock on storage pool

hyperscale_add_nodes()      --  Add 3 new nodes to an existing storage pool

StoragePool instance attributes

**storage_pool_name**           --  returns the name of the storage pool

**storage_pool_id**             --  returns the storage pool id

**storage_pool_properties**     --  returns the properties of the storage pool

**global_policy_name**          --  returns the global policy corresponding to the storage pool

**copy_name**                   --  returns the copy name of the storage pool

**copy_id**                     --  returns the copy id of the storage pool

**storage_pool_type**           --  returns the storage pool type

**storage_type**                --  returns the storage type of the storage pool

**storage_vendor**              --  returns the storage vendor id of the storage pool

**is_worm_storage_lock_enabled**--  returns whether WORM storage lock is enabled

**is_object_level_worm_lock_enabled** --  returns whether object level WORM lock is enabled

**is_bucket_level_worm_lock_enabled** --  returns whether bucket level WORM lock is enabled

**is_compliance_lock_enabled**  --  returns whether compliance lock is enabled

TODO: check with MM API team to get the response in JSON

Expand source code Browse git
# -*- coding: utf-8 -*-

# --------------------------------------------------------------------------
# Copyright Commvault Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# --------------------------------------------------------------------------

"""File for doing operations on an Storage Pools.

This module has classes defined for doing operations for Storage Pools:

StoragePools, StoragePoolType, StorageType, WORMLockType and StoragePool are the classes defined in this file.

StoragePools: Class for representing all the StoragePools in the commcell

StoragePoolType : Class for representing storage pool types like deduplication, secondary copy, non-dedupe, scale out

StorageType : Class for representing storage types like disk, cloud, tape of a storage pool

WORMLockType : Class for representing different WORM lock types flag values of a WORM enable storage pool

StoragePool: Class for representing a single StoragePool of the commcell


StoragePools
============

    __init__(commcell_object)   --  initializes object of the StoragePools class associated with the commcell

    __str__()                   --  returns all the storage pools associated with the commcell

    __repr__()                  --  returns the string representation of an instance of this class

    __len__()                   --  returns the number of storage pools added to the Commcell

    __getitem__()               --  returns the name of the storage pool for the given storage
    pool Id or the details for the given storage pool name

    _get_storage_pools()        --  returns all storage pools added to the commcell

    has_storage_pool()          --  checks whether the storage pool  with given name exists or not

    get()                       --  returns StoragePool object of the storage pool for the
                                    specified input name

    add()                       --  Adds a storage pool, according to given input and returns
                                    StoragePool object

    delete()                    --  deletes the specified storage pool

    refresh()                   --  refresh the list of storage pools associated with the commcell

    add_air_gap_protect()       --  Adds a new air gap protect storage pool to commcell

Attributes
----------

    **all_storage_pools**   --  returns dict of all the storage pools on commcell


StoragePool
===========

    __init__()                  --  initialize the instance of StoragePool class for specific storage pool of commcell

    __repr__()                  --  returns a string representation of the StoragePool instance

     _get_storage_pool_properties() --  returns the properties of this storage pool

    refresh()                   --      Refresh the properties of the StoragePool

    get_copy()                  --  Returns the StoragePolicyCopy object of Storage Pool copy

    enable_compliance_lock()    --  Enables compliance lock on Storage Pool Copy

    enable_worm_storage_lock()  --  Enables WORM storage lock on storage pool

    hyperscale_add_nodes()      --  Add 3 new nodes to an existing storage pool

StoragePool instance attributes
================================

    **storage_pool_name**           --  returns the name of the storage pool

    **storage_pool_id**             --  returns the storage pool id

    **storage_pool_properties**     --  returns the properties of the storage pool

    **global_policy_name**          --  returns the global policy corresponding to the storage pool

    **copy_name**                   --  returns the copy name of the storage pool

    **copy_id**                     --  returns the copy id of the storage pool

    **storage_pool_type**           --  returns the storage pool type

    **storage_type**                --  returns the storage type of the storage pool

    **storage_vendor**              --  returns the storage vendor id of the storage pool

    **is_worm_storage_lock_enabled**--  returns whether WORM storage lock is enabled

    **is_object_level_worm_lock_enabled** --  returns whether object level WORM lock is enabled

    **is_bucket_level_worm_lock_enabled** --  returns whether bucket level WORM lock is enabled

    **is_compliance_lock_enabled**  --  returns whether compliance lock is enabled

# TODO: check with MM API team to get the response in JSON

"""
import copy

import xmltodict
from base64 import b64encode
from enum import IntFlag, IntEnum

from .exception import SDKException

from .storage import MediaAgent
from .security.security_association import SecurityAssociation
from .constants import StoragePoolConstants
from .policies.storage_policies import StoragePolicyCopy

class StorageType(IntEnum):
    """Class IntEnum to represent different storage types"""
    DISK = 1,
    CLOUD = 2,
    HYPERSCALE = 3,
    TAPE = 4

class StoragePools:
    """Class for doing operations on Storage Pools, like get storage poo ID."""

    def __init__(self, commcell_object):
        """Initializes instance of the StoragePools class to perform operations on a storage pool.

            Args:
                commcell_object     (object)    --  instance of the Commcell class

            Returns:
                object  -   instance of the StoragePools class

        """
        self._commcell_object = commcell_object

        self._cvpysdk_object = commcell_object._cvpysdk_object
        self._services = commcell_object._services
        self._update_response_ = commcell_object._update_response_
        self._add_storage_pool_api = self._services['ADD_STORAGE_POOL']

        self._storage_pools_api = self._services['STORAGE_POOL']

        self._metallic_storage_api = self._services['GET_METALLIC_STORAGE_DETAILS']
        self.__get_agp_storage_api = self._services['GET_AGP_STORAGE']
        self._storage_pools = None

        self.refresh()

    def __str__(self):
        """Representation string consisting of all storage pools present in the Commcell.

            Returns:
                str     -   string of all the storage pools associated with the commcell

        """
        representation_string = '{:^5}\t{:^40}\n\n'.format('S. No.', 'Storage Pool')

        for index, storage_pool in enumerate(self._storage_pools):
            sub_str = '{:^5}\t{:40}\n'.format(index + 1, storage_pool)
            representation_string += sub_str

        return representation_string.strip()

    def __repr__(self):
        """Returns the string representation of an instance of this class."""
        return "StoragePools class instance for Commcell"

    def __len__(self):
        """Returns the number of the storage pools added to the Commcell."""
        return len(self.all_storage_pools)

    def __getitem__(self, value):
        """Returns the name of the storage pool for the given storage pool ID or
            the details of the storage pool for given storage pool Name.

            Args:
                value   (str / int)     --  Name or ID of the storage pool

            Returns:
                str     -   name of the storage pool, if the storage pool id was given

                dict    -   dict of details of the storage pool, if storage pool name was given

            Raises:
                IndexError:
                    no storage pool exists with the given Name / Id

        """
        value = str(value)

        if value in self.all_storage_pools:
            return self.all_storage_pools[value]
        else:
            try:
                return list(filter(lambda x: x[1]['id'] == value, self.all_storage_pools.items()))[0][0]
            except IndexError:
                raise IndexError('No storage pool exists with the given Name / Id')

    def _get_storage_pools(self):
        """Gets all the storage pools associated with the Commcell environment.

            Returns:
                dict    -   consists of all storage pools added to the commcell

                    {
                        "storage_pool1_name": storage_pool1_id,

                        "storage_pool2_name": storage_pool2_id
                    }

            Raises:
                SDKException:
                    if response is empty

                    if response is not success

        """
        headers = self._commcell_object._headers.copy()
        headers['Accept'] = 'application/xml'

        flag, response = self._cvpysdk_object.make_request(
            'GET', self._storage_pools_api, headers=headers
        )

        if flag:
            storage_pools = {}

            response = xmltodict.parse(response.text)['Api_GetStoragePoolListResp']

            if response is None or response.get('storagePoolList') is None:
                storage_pool_list = []
            else:
                storage_pool_list = response['storagePoolList']

            if not isinstance(storage_pool_list, list):
                storage_pool_list = [storage_pool_list]

            if response:
                for pool in storage_pool_list:
                    name = pool['storagePoolEntity']['@storagePoolName'].lower()
                    storage_pool_id = pool['storagePoolEntity']['@storagePoolId']

                    storage_pools[name] = storage_pool_id

                return storage_pools
        else:
            response_string = self._update_response_(response.text)
            raise SDKException('Response', '101', response_string)
    
    def get_storage_pools_for_a_company(self, company_id, storage_type: StorageType = None):
        """Gets all the storage pools associated with the Commcell environment.

            Args:
                company_id - id of the company for which the associated storge pools are to be fetched

            Returns:
                dict    -   consists of all storage pools added to the commcell

                    {
                        "storage_pool1_name": storage_pool1_id,

                        "storage_pool2_name": storage_pool2_id
                    }

            Raises:
                SDKException:
                    if response is empty

                    if response is not success

        """
        headers = self._commcell_object._headers.copy()
        headers['Accept'] = 'application/json'
        headers['onlygetcompanyownedentities'] = '1'
        headers['operatorcompanyid'] = f'{company_id}'

        flag, response = self._cvpysdk_object.make_request(
            'GET', self._storage_pools_api, headers=headers
        )

        if flag:
            storage_pools = {}
            response = response.json()
            if response is None or response.get('storagePoolList') is None:
                storage_pool_list = []
            else:
                storage_pool_list = response['storagePoolList']
            if not isinstance(storage_pool_list, list):
                storage_pool_list = [storage_pool_list]
            if response:
                for pool in storage_pool_list:
                    if storage_type and pool['storageType'] != storage_type:
                        continue
                    # skip agp pools for cloud storage type
                    if storage_type == StorageType.CLOUD and 401 <= pool['libraryVendorType'] <= 499:
                        continue
                    name = pool['storagePoolEntity']['storagePoolName']
                    storage_pool_id = pool['storagePoolEntity']['storagePoolId']

                    storage_pools[name] = storage_pool_id

            return storage_pools
        else:
            response_string = self._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

    @property
    def all_storage_pools(self):
        """Returns dict of all the storage pools on this commcell

            dict    -   consists of all storage pools added to the commcell

                {

                    "storage_pool1_name": storage_pool1_id,

                    "storage_pool2_name": storage_pool2_id
                }

        """
        return self._storage_pools

    def has_storage_pool(self, name):
        """Checks if a storage pool exists in the Commcell with the input storage pool name.

            Args:
                name    (str)   --  name of the storage pool

            Returns:
                bool    -   boolean output whether the storage pool exists in the commcell or not

        """
        return self._storage_pools and name.lower() in self._storage_pools

    def get(self, name):
        """Returns the id of the storage pool for the given storage pool name.

            Args:
                name    (str)   --  name of the storage pool to get the id of

            Returns:
                str     -   id of the storage pool for the given storage pool name

            Raises:
                SDKException:
                    if no storage pool exists with the given name

        """
        self.refresh()
        name = name.lower()

        if self.has_storage_pool(name):
            return StoragePool(self._commcell_object, name, storage_pool_id=self._storage_pools[name])
        else:
            raise SDKException('StoragePool', '103')

    def hyperscale_create_storage_pool(self, storage_pool_name, media_agents):
        """
            Create new storage pool for hyperscale
            Args:
                storage_pool_name (string) -- Name of the storage pools to create

                media_agents      (List)   -- List of 3 media agents with name's(str)
                                                or instance of media agent's(object)

                Example: ["ma1","ma2","ma3"]

            Return:
                 flag, response -- response returned by the REST API call
        """

        if not isinstance(media_agents, list):
            raise SDKException('Storage', '101')
        if not isinstance(storage_pool_name, str):
            raise SDKException('Storage', '101')

        mediagent_obj = []
        for media_agent in media_agents:
            if isinstance(media_agent, MediaAgent):
                mediagent_obj.append(media_agent)
            elif isinstance(media_agent, str):
                mediagent_obj.append(self._commcell_object.media_agents.get(media_agent))
            else:
                raise SDKException('Storage', '103')
        if len(mediagent_obj) <= 2:
            raise SDKException('Storage', '102', "minimum 3 media agents are required")

        request_xml = """<App_CreateStoragePolicyReq storagePolicyName="{0}" copyName="{0}_Primary" type="1"
                                     numberOfCopies="1">
                                    <storagePolicyCopyInfo>
                                        <storagePolicyFlags scaleOutStoragePolicy="1"/>
                                    </storagePolicyCopyInfo>
                                    <storage>
                                        <mediaAgent mediaAgentId="{4}" mediaAgentName="{1}" displayName="{1}"/>
                                    </storage>
                                    <storage>
                                        <mediaAgent mediaAgentId="{5}" mediaAgentName="{2}" displayName="{2}"/>
                                    </storage>
                                    <storage>
                                        <mediaAgent mediaAgentId="{6}" mediaAgentName="{3}" displayName="{3}"/>
                                    </storage>
                                    <scaleoutConfiguration configurationType="1"/>
                                </App_CreateStoragePolicyReq>
                                """.format(storage_pool_name, mediagent_obj[0].media_agent_name,
                                           mediagent_obj[1].media_agent_name, mediagent_obj[2].media_agent_name,
                                           mediagent_obj[0].media_agent_id, mediagent_obj[1].media_agent_id,
                                           mediagent_obj[2].media_agent_id)

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._add_storage_pool_api, request_xml
        )
        if flag:
            if response.json():
                error_code = response.json()['error']['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['error']['errorMessage']
                    o_str = 'Failed to create storage pool\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()
        return self.get(storage_pool_name)

    def add_air_gap_protect(self, storage_pool_name, media_agent, storage_type, storage_class, region_name,
                            ddb_ma=None, dedup_path=None):
        """
            Adds a new air gap protect storage pool to commcell

                Args:
                    storage_pool_name   (str)       --  name of new storage pool to add

                    media_agent         (str/object)--  name or instance of media agent

                    storage_type        (str)        -- name of the cloud vendor (str, eg - "Microsoft Azure storage") (same as UI)

                    storage_class       (str)        -- storage class (str, eg - "Hot","Cool") (same as UI)

                    region_name (str)      --  name of the geographical region for storage (same as UI)

                    ddb_ma              (list<str/object>/str/object)   --  list of (name of name or instance)
                                                                            or name or instance of dedupe media agent

                    dedup_path          (list<str>/str)       --  list of paths or path where the DDB should be stored

                Returns:
                    StoragePool object if creation is successful

                Raises:
                    SDKException, if invalid parameters provided

        """
        license_type_dict = StoragePoolConstants.AIR_GAP_PROTECT_STORAGE_TYPES
        error_message = ""
        if storage_type.upper() in license_type_dict:
            available_storage_classes = license_type_dict[storage_type.upper()]
            if storage_class.upper() in available_storage_classes:
                vendor_id = available_storage_classes[storage_class.upper()]["vendorId"]
                display_vendor_id = available_storage_classes[storage_class.upper()]["displayVendorId"]
            else:
                error_message += f"Invalid storage class provided. Valid storage class {list(available_storage_classes.keys())}"
        else:
            error_message += f"  Invalid storage type provided. {list(license_type_dict.keys())}"

        if error_message:
            raise SDKException('Storage', '101', error_message)

        region = None
        available_regions = []

        #  API call to fetch the region name - sourced directly from the vendor
        flag, response = self._commcell_object._cvpysdk_object.make_request('GET', self._metallic_storage_api)
        if flag:
            if response.json():
                if "storageInformation" in response.json():
                    for storage_info in response.json()["storageInformation"]:
                        if (int(storage_info["vendorId"]) == int(vendor_id)) and (int(storage_info["displayVendorId"]) == int(display_vendor_id)):
                            for region_dict in storage_info["region"]:
                                available_regions.append(region_dict["displayName"])
                                if region_dict["displayName"] == region_name:
                                    region = region_dict["regionName"]
                                    break

                        if region:
                            break

                    if region is None:
                        if not available_regions:
                            raise SDKException('Storage', '101',
                                               f"Active license is required to configure {storage_type} - {storage_class} Air Gap Protect storage")
                        else:
                            raise SDKException('Storage', '101',
                                               f"Invalid region: {region_name} ,\nValid regions: {available_regions}")
                else:
                    raise SDKException('Storage', '101', "Unexpected response returned while fetching Air Gap Protect storage details")
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        # cloud server type for air gap protect is 400
        cloud_server_type = 400

        return self.add(storage_pool_name=storage_pool_name, mountpath=None, media_agent=media_agent, ddb_ma=ddb_ma,
                        dedup_path=dedup_path, cloud_server_type=cloud_server_type, region=region, vendor_id=vendor_id,
                        display_vendor_id=display_vendor_id)
        
    def get_air_gap_protect(self, company_id = None):
        """
        Returns the list of air gap protect storage pools in the commcell.
        
        Args:
            company_id (int) -- id of the company to get the air gap protect storage pools for
                                (optional, default is None which returns all air gap protect storage pools)
        
        Returns:
            dict - dictionary of air gap protect storage pools with name as key and id as value
                
                    {
                        "storage_pool1_name": storage_pool1_id,
                        "storage_pool2_name": storage_pool2_id
                    }  
        
        Raises:
            SDKException:
                if response is empty

                if response is not success
        """
        headers = self._commcell_object._headers.copy()
        headers['Accept'] = 'application/json'
        if company_id:
            headers['onlygetcompanyownedentities'] = '1'
            headers['operatorcompanyid'] = f'{company_id}'

        flag, response = self._cvpysdk_object.make_request(
            'GET', self.__get_agp_storage_api, headers=headers
        )

        if flag:
            storage_pools = {}
            response = response.json()
            if response is None or response.get('cloudStorage') is None:
                storage_pool_list = []
            else:
                storage_pool_list = response['cloudStorage']
            if not isinstance(storage_pool_list, list):
                storage_pool_list = [storage_pool_list]
            if response:
                for pool in storage_pool_list:
                    name = pool['name']
                    storage_pool_id = pool['id']

                    storage_pools[name] = storage_pool_id

            return storage_pools
        else:
            response_string = self._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

    def add(self, storage_pool_name, mountpath, media_agent, ddb_ma=None, dedup_path=None, **kwargs):
        """
        Adds a new storage pool to commcell

        Args:
            storage_pool_name   (str)       --  name of new storage pool to add

            mountpath           (str)       --  mount path for the storage pool

            media_agent         (str/object)--  name or instance of media agent

            ddb_ma              (list<str/object>/str/object)   --  list of (name of name or instance)
                                                                        or name or instance of dedupe media agent

            dedup_path          (list<str>/str)       --  list of paths or path where the DDB should be stored

            **kwargs:
                username        (str)       --  username to access the mountpath

                password        (str)       --  password to access the mountpath

                credential_name (str)       --  name of the credential as in credential manager

                cloud_server_type (int)     --  cloud server type of the cloud vendor (required)

                region (str)                --  name of geographical region for storage (required for air gap protect)

                vendor_id (int)             -- id for the cloud_vendor (eg - 3 for azure) (required for air gap protect pool)

                display_vendor_id (int)     -- storage Class id for that vendor (eg - 401 for azure hot) (required for air gap protect pool)

                region_id        (int)      --  Cloud Hypervisor specific region ID

                tape_storage (boolean)      -- if library passed is tape library. 

        Returns:
            StoragePool object if creation is successful

        Raises:
            Exception if creation is unsuccessful
        """
        username = kwargs.get('username', None)
        password = kwargs.get('password', None)
        credential_name = kwargs.get('credential_name', None)
        cloud_server_type = kwargs.get('cloud_server_type', None)
        library_name = kwargs.get('library_name', None)
        tape_storage = False

        region = kwargs.get('region', None)
        vendor_id = kwargs.get('vendor_id', None)
        display_vendor_id = kwargs.get('display_vendor_id', None)
        region_id = kwargs.get('region_id', None)

        if library_name:
            library_object = self._commcell_object.disk_libraries.get(library_name)
            library_type = library_object.library_properties.get('libraryType', None)
            tape_storage = True if library_type == 1 else tape_storage


        if ((ddb_ma is not None and not (isinstance(dedup_path, str) or isinstance(dedup_path, list))) or
                not (isinstance(storage_pool_name, str) or not isinstance(mountpath, str))):
            raise SDKException('Storage', '101')

        if isinstance(media_agent, MediaAgent):
            media_agent = media_agent
        elif isinstance(media_agent, str):
            media_agent = MediaAgent(self._commcell_object, media_agent)
        else:
            raise SDKException('Storage', '103')

        if (isinstance(ddb_ma, str) or isinstance(ddb_ma, MediaAgent)) and isinstance(dedup_path, str):
            ddb_ma = [ddb_ma]
            dedup_path = [dedup_path]

        if isinstance(ddb_ma, list) and isinstance(dedup_path, list):
            if len(ddb_ma) != len(dedup_path):
                raise SDKException('Storage', '101')

        if library_name is not None and mountpath != '':
            raise SDKException('Storage', '101')

        if ddb_ma is not None and (len(ddb_ma) > 6 or len(dedup_path) > 6):
            raise SDKException('Storage', '110')

        if ddb_ma is not None:
            for i in range(len(ddb_ma)):
                if isinstance(ddb_ma[i], MediaAgent):
                    ddb_ma[i] = ddb_ma[i]
                elif isinstance(ddb_ma[i], str):
                    ddb_ma[i] = MediaAgent(self._commcell_object, ddb_ma[i])
                else:
                    raise SDKException('Storage', '103')

        request_json = {
            "storagePolicyName": storage_pool_name,
            "type": "CVA_REGULAR_SP",
            "copyName": "Primary",
            "numberOfCopies": 1,
            "storage": [
                {
                    "path": mountpath,
                    "mediaAgent": {
                        "mediaAgentId": int(media_agent.media_agent_id),
                        "mediaAgentName": media_agent.media_agent_name
                    }
                }
            ],
            "storagePolicyCopyInfo": {
                "copyType": "SYNCHRONOUS",
                "isFromGui": True,
                "active": "SET_TRUE",
                "isDefault": "SET_TRUE",
                "numberOfStreamsToCombine": 1,
                "retentionRules": {
                    "retentionFlags": {
                        "enableDataAging": "SET_TRUE"
                    },
                    "retainBackupDataForDays": -1,
                    "retainBackupDataForCycles": -1,
                    "retainArchiverDataForDays": -1
                },
                "library": {
                    "libraryId": 0,
                },
                "mediaAgent": {
                    "mediaAgentId": int(media_agent.media_agent_id),
                    "mediaAgentName": media_agent.media_agent_name
                }
            }
        }

        if cloud_server_type and int(cloud_server_type) > 0:
            request_json["storage"][0]["deviceType"] = cloud_server_type

        if region_id is not None:
            request_json["storage"][0]["metallicStorageInfo"] = {
                "region": [
                    {
                        "regionId": region_id
                    }
                ],
                "storageClass": [
                    "CONTAINER_DEFAULT"
                ],
                "replication": [
                    "NONE"
                ]
            }
            request_json["region"] = {"regionId": region_id}

        if username is not None:
            request_json["storage"][0]["credentials"] = {"userName": username}

        if password is not None:
            request_json["storage"][0]["credentials"]["password"] = b64encode(password.encode()).decode()

        if credential_name is not None:
            request_json["storage"][0]["savedCredential"] = {"credentialName": credential_name}

        if library_name is not None:
            request_json["storage"] = []
            request_json["storagePolicyCopyInfo"]["library"]["libraryName"] = library_name

        if ddb_ma is not None or dedup_path is not None:
            maInfoList = []
            for ma, path in zip(ddb_ma, dedup_path):
                maInfoList.append({
                    "mediaAgent": {
                        "mediaAgentId": int(ma.media_agent_id),
                        "mediaAgentName": ma.media_agent_name
                    },
                    "subStoreList": [
                        {
                            "accessPath": {
                                "path": path
                            },
                            "diskFreeThresholdMB": 5120,
                            "diskFreeWarningThreshholdMB": 10240
                        }]
                })

            request_json["storagePolicyCopyInfo"].update({
                "storagePolicyFlags": {
                    "blockLevelDedup": "SET_TRUE",
                    "enableGlobalDeduplication": "SET_TRUE"
                },
                "dedupeFlags": {
                    "enableDeduplication": "SET_TRUE",
                    "enableDASHFull": "SET_TRUE",
                    "hostGlobalDedupStore": "SET_TRUE"
                },
                "DDBPartitionInfo": {
                    "maInfoList": maInfoList
                }
            })
        elif tape_storage:
            request_json["storagePolicyCopyInfo"].update({
                "storagePolicyFlags": {
                    "globalAuxCopyPolicy": "SET_TRUE"
                },
                "copyFlags": {
                    "preserveEncryptionModeAsInSource": "SET_TRUE"
                },
                "extendedFlags": {
                    "globalAuxCopyPolicy": "SET_TRUE"
                }
            })
        else:
            request_json["storagePolicyCopyInfo"].update({
                "storagePolicyFlags": {
                    "globalStoragePolicy": "SET_TRUE"
                },
                "copyFlags": {
                    "preserveEncryptionModeAsInSource": "SET_TRUE"
                },
                "extendedFlags": {
                    "globalStoragePolicy": "SET_TRUE"
                }
            })

        # air gap protect storage
        if cloud_server_type == 400:
            del request_json["storage"][0]["path"]
            request_json["storage"][0]["savedCredential"] = {"credentialId": 0}

            metallic_Storage = {
                "region": [
                    {
                        "regionName": region
                    }
                ],
                "displayVendorId": display_vendor_id,
                "vendorId": vendor_id
            }
            request_json["storage"][0]["metallicStorageInfo"] = metallic_Storage

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._add_storage_pool_api, request_json
        )

        if flag:
            if response.json():
                error_code = response.json()['error']['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['error']['errorMessage']
                    o_str = 'Failed to create storage pool\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()
        self._commcell_object.disk_libraries.refresh()
        return self.get(storage_pool_name)

    def delete(self, storage_pool_name):
        """deletes the specified storage pool.

            Args:
                storage_pool_name (str)  --  name of the storage pool to delete

            Raises:
                SDKException:
                    if type of the storage pool name is not string

                    if failed to delete storage pool

                    if no storage pool exists with the given name

                    if response is empty

                    if response is not success

        """

        if not isinstance(storage_pool_name, str):
            raise SDKException('Storage', '101')
        else:
            storage_pool_name = storage_pool_name.lower()

            if self.has_storage_pool(storage_pool_name):
                storage_pool_id = self._storage_pools[storage_pool_name]

                delete_storage_pool = self._services['DELETE_STORAGE_POOL'] % (storage_pool_id)

                flag, response = self._cvpysdk_object.make_request('DELETE', delete_storage_pool)

                if flag:
                    error_code = response.json()['error']['errorCode']
                    if int(error_code) != 0:
                        error_message = response.json()['error']['errorMessage']
                        o_str = f'Failed to delete storage pools {storage_pool_name}'
                        o_str += '\nError: "{0}"'.format(error_message)
                        raise SDKException('Storage', '102', o_str)
                    else:
                        # initialize the storage pool again
                        # so the storage pool object has all the storage pools
                        self.refresh()
                        # as part of storage pool we might delete library so initialize the libraries again
                        self._commcell_object.disk_libraries.refresh()
                else:
                    response_string = self._update_response_(response.text)
                    raise SDKException('Response', '101', response_string)
            else:
                raise SDKException(
                    'Storage',
                    '102',
                    'No storage pool exists with name: {0}'.format(storage_pool_name)
                )
    def refresh(self):
        """Refresh the list of storage pools associated to the Commcell."""
        self._storage_pools = self._get_storage_pools()

class StoragePoolType(IntEnum):
    """Class IntEnum to represent different storage pool types"""
    DEDUPLICATION = 1,
    SECONDARY_COPY = 2,
    NON_DEDUPLICATION = 3,
    SCALE_OUT = 4


class WORMLockType(IntFlag):
    """Class IntFlag to represent different WORM lock types flag values"""
    COPY = 1,  # copy level software WORM (compliance lock)
    STORAGE = 2,  # storage level hardware WORM
    OBJECT = 4,  # object level storage WORM
    BUCKET = 8  # bucket level storage WORM


class StoragePool(object):
    """Class for individual storage pools"""

    def __init__(self, commcell_object, storage_pool_name, storage_pool_id=None):
        """
        Intitalise the Storage Pool classs instance

        Args:
            commcell_object     (object)        --instance of the Commcell class

            storage_pool_name   (string)    -- Name of the storage pool

            storage_pool_id     (int)       -- Storage pool id
        Returns:
            object - Instance of the StoragePool class

        """
        self._storage_pool_name = storage_pool_name.lower()
        self._commcell_object = commcell_object
        self._storage_pool_properties = None
        self._storage_pool_id = None
        self._copy_id = None
        self._copy_name = None

        if storage_pool_id:
            self._storage_pool_id = str(storage_pool_id)
        else:
            self._storage_pool_id = self._commcell_object.storage_pools.get(self._storage_pool_name).storage_pool_id

        self._STORAGE_POOL = self._commcell_object._services['GET_STORAGE_POOL'] % (self.storage_pool_id)
        self.refresh()

        self._copy_id = self._storage_pool_properties.get("storagePoolDetails", {}).get("copyInfo", {}).get(
            "StoragePolicyCopy", {}).get("copyId")
        self._copy_name = self._storage_pool_properties.get("storagePoolDetails", {}).get("copyInfo", {}).get(
            "StoragePolicyCopy", {}).get("copyName")

    def __repr__(self):
        """String representation of the instance of this class"""
        representation_string = "Storage Pool class Instance for {0}".format(self._storage_pool_name)
        return representation_string

    def _get_storage_pool_properties(self):
        """
        Gets StoragePool properties

            Raises:
                SDKException:
                    if repsonse is empty

                    if response is not success

        """
        flag, response = self._commcell_object._cvpysdk_object.make_request('GET', self._STORAGE_POOL)

        if flag:
            if response.json():
                self._storage_pool_properties = response.json()
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

    @property
    def storage_pool_name(self):
        """Treats the storage_policy_name as a read only attribute"""
        return self._storage_pool_name

    @property
    def storage_pool_id(self):
        """Treats id as a read only attribute"""
        return self._storage_pool_id

    @property
    def storage_pool_properties(self):
        """Treats the storage_pool_properties as a read only attribute"""
        return self._storage_pool_properties

    @property
    def global_policy_name(self):
        """Returns the global policy corresponding to the storage pool"""
        return self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["StoragePolicyCopy"]["storagePolicyName"]

    @property
    def copy_name(self):
        """Treats copy name as a read only attribute"""
        return self._copy_name

    @property
    def copy_id(self):
        """Treats copy ID as a read only attribute"""
        return self._copy_id

    @property
    def storage_pool_type(self):
        """Treats storage type as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["storagePoolType"]

    @property
    def storage_type(self):
        """Treats storage type as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["storageType"]

    @property
    def storage_vendor(self):
        """Treats library vendor like cloud storage provider as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["libraryVendorId"]

    @property
    def is_worm_storage_lock_enabled(self):
        """Treats is worm enabled as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["isWormStorage"]

    @property
    def is_object_level_worm_lock_enabled(self):
        """Treats is object WORM enabled as a read only attribute"""
        worm_flag = int(self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["wormStorageFlag"])
        return worm_flag & WORMLockType.OBJECT == WORMLockType.OBJECT

    @property
    def is_bucket_level_worm_lock_enabled(self):
        """Treats is bucket WORM enabled as a read only attribute"""
        worm_flag = int(self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["wormStorageFlag"])
        return worm_flag & WORMLockType.BUCKET == WORMLockType.BUCKET

    @property
    def is_compliance_lock_enabled(self):
        """Treats is compliance lock enabled as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["copyFlags"]["wormCopy"] == 1

    def get_copy(self):
        """ Returns the StoragePolicyCopy object of Storage Pool copy"""
        return StoragePolicyCopy(self._commcell_object, self.storage_pool_name, self.copy_name)

    def enable_compliance_lock(self):
        """ Enables compliance lock on Storage Pool Copy """
        self.get_copy().enable_compliance_lock()
        self.refresh()

    def enable_worm_storage_lock(self, retain_days):
        """
        Enable storage WORM lock on storage pool

        Args:
            retain_days    (int)   -- number of days of retention on WORM copy.

        Raises:
            SDKException:
                if response is not success.

                if reponse is empty.
        """

        request_json = {
            "storagePolicyCopyInfo": {
                "copyFlags": {
                    "wormCopy": 1
                },
                "retentionRules": {
                    "retainBackupDataForDays": retain_days
                }
            },
            "isWormStorage": True,
            "forceCopyToFollowPoolRetention": True
        }

        _STORAGE_POOL_COPY = self._commcell_object._services['STORAGE_POLICY_COPY'] % (
            self._storage_pool_id, str(self.copy_id))
        flag, response = self._commcell_object._cvpysdk_object.make_request('PUT', _STORAGE_POOL_COPY, request_json)

        if flag:
            if response.json():
                response = response.json()
                if "error" in response and response.get("error", {}).get("errorCode") != 0:
                    error_message = response.get("error", {}).get("errorMessage")
                    raise SDKException('Response', '102', error_message)
                else:
                    self.refresh()
            else:
                raise SDKException('Response', '101')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

    def hyperscale_add_nodes(self, media_agents):
        """
        Add 3 new nodes to an existing storage pool

        args:
            media_agents      (List)   -- List of 3 media agents with name's(str)
                                            or instance of media agent's(object)

            Example: ["ma1","ma2","ma3"]

        Raises:
                SDKException:
                    if add nodes to an existing storage pool fails
        """
        if not isinstance(media_agents, list):
            raise SDKException('Storage', '101')

        mediagent_obj = []
        for media_agent in media_agents:
            if isinstance(media_agent, MediaAgent):
                mediagent_obj.append(media_agent)
            elif isinstance(media_agent, str):
                mediagent_obj.append(self._commcell_object.media_agents.get(media_agent))
            else:
                raise SDKException('Storage', '103')

        if len(mediagent_obj) <= 2:
            raise SDKException('Storage', '102', "Minimum 3 MediaAgents required")

        request_json = {
            "scaleoutOperationType": 2,
            "StoragePolicy": {
                "storagePolicyName": "{0}".format(self.storage_pool_name),
            },
            "storage": [
                {
                    "mediaAgent": {
                        "displayName": "{0}".format(mediagent_obj[0].media_agent_id),
                        "mediaAgentName": "{0}".format(mediagent_obj[0].media_agent_name)
                    }
                },
                {
                    "mediaAgent": {
                        "displayName": "{0}".format(mediagent_obj[1].media_agent_id),
                        "mediaAgentName": "{0}".format(mediagent_obj[1].media_agent_name)
                    }
                },
                {
                    "mediaAgent": {
                        "displayName": "{0}".format(mediagent_obj[2].media_agent_id),
                        "mediaAgentName": "{0}".format(mediagent_obj[2].media_agent_name)
                    }
                }
            ],
            "scaleoutConfiguration": {
                "configurationType": 1
            }
        }

        self._edit_storage_pool_api = self._commcell_object._services[
            'EDIT_STORAGE_POOL']

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._edit_storage_pool_api, request_json
        )

        if flag:
            if response.json():
                error_code = response.json()['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['errorMessage']
                    o_str = 'Failed to add nodes to storage pool\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()

    def hyperscale_reconfigure_storage_pool(self, storage_pool_name):
        """
        Reconfigures storage pool, for any failure during creation and expansion

        args:
          storage_pool_name (string) -- Name of the storage pools to reconfigure
        Raises:
                SDKException:
                    if reconfigure fails
        """
        if not isinstance(storage_pool_name, str):
            raise SDKException('Storage', '101')

        request_json = {

            "scaleoutOperationType": 4,
            "StoragePolicy":
                {
                    "storagePolicyName": "{0}".format(storage_pool_name),
                    "storagePolicyId": int("{0}".format(self.storage_pool_id))

                }
        }

        self._edit_storage_pool_api = self._commcell_object._services[
            'EDIT_STORAGE_POOL']

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._edit_storage_pool_api, request_json
        )

        if flag:
            if response.json():
                error_code = response.json()['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['errorMessage']
                    o_str = 'Failed to reconfigure storage pool\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()

    def hyperscale_replace_disk(self, disk_id, media_agent, storage_pool_name):
        """
              Replace disk action, over a media agent which is part of storage pool
               args:
                    disk_id (int) --> disk id for the disk to replace
                    media_agent (string/object) --> media agent name/ object
                    storage_pool_name (string) --> Name of the storage pools for replacemnet of disk
               Raises:
                       SDKException:
                           if replace fails
               """
        if isinstance(disk_id, str):
            disk_id = int(disk_id)
        elif not isinstance(disk_id, int):
            raise SDKException('Storage', '101')

        media_agent_obj = None
        if isinstance(media_agent, str):
            media_agent_obj = self._commcell_object.media_agents.get(media_agent)
        elif isinstance(media_agent, MediaAgent):
            media_agent_obj = media_agent
        else:
            raise SDKException('Storage', '103')

        if not isinstance(storage_pool_name, str):
            raise SDKException('Storage', '101')

        request_json = {

            "driveId": int("{0}".format(disk_id)),
            "operationType": 1,
            "mediaAgent": {
                "_type_": 11,
                "mediaAgentId": int("{0}".format(media_agent_obj.media_agent_id)),
                "mediaAgentName": "{0}".format(media_agent_obj.media_agent_name)
            },
            "scaleoutStoragePool": {
                "_type_": 160,
                "storagePoolId": int("{0}".format(self.storage_pool_id)),
                "storagePoolName": "{0}".format(self.storage_pool_name)
            }
        }

        self._replace_disk_storage_pool_api = self._commcell_object._services[
            'REPLACE_DISK_STORAGE_POOL']

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._replace_disk_storage_pool_api, request_json
        )

        if flag:
            if response.json():
                error_code = response.json()['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['errorMessage']
                    o_str = 'Failed to replace disk\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()

    def refresh(self):
        """Refreshes propery of the class object"""
        self._get_storage_pool_properties()

    def update_security_associations(self, associations_list, isUser=True, request_type=None, externalGroup=False):
        """
        Adds the security association on the storage pool object

        Args:
            associations_list   (list)  --  list of users to be associated
                Example:
                    associations_list = [
                        {
                            'user_name': user1,
                            'role_name': role1
                        },
                        {
                            'user_name': user2,
                            'role_name': role2
                        }
                    ]

            isUser (bool)           --    True or False. set isUser = False, If associations_list made up of user groups
            request_type (str)      --    eg : 'OVERWRITE' or 'UPDATE' or 'DELETE', Default will be OVERWRITE operation
            externalGroup (bool)    --    True or False, set externalGroup = True. If Security associations is being done on External User Groups

        Raises:
            SDKException:
                if association is not of List type
        """
        if not isinstance(associations_list, list):
            raise SDKException('StoragePool', '101')

        SecurityAssociation(self._commcell_object, self)._add_security_association(associations_list,
                                                                                   user=isUser,
                                                                                   request_type=request_type,
                                                                                   externalGroup=externalGroup)

Classes

class StoragePool (commcell_object, storage_pool_name, storage_pool_id=None)

Class for individual storage pools

Intitalise the Storage Pool classs instance

Args

commcell_object (object) –instance of the Commcell class

storage_pool_name (string) – Name of the storage pool

storage_pool_id (int) – Storage pool id

Returns

object - Instance of the StoragePool class

Expand source code Browse git
class StoragePool(object):
    """Class for individual storage pools"""

    def __init__(self, commcell_object, storage_pool_name, storage_pool_id=None):
        """
        Intitalise the Storage Pool classs instance

        Args:
            commcell_object     (object)        --instance of the Commcell class

            storage_pool_name   (string)    -- Name of the storage pool

            storage_pool_id     (int)       -- Storage pool id
        Returns:
            object - Instance of the StoragePool class

        """
        self._storage_pool_name = storage_pool_name.lower()
        self._commcell_object = commcell_object
        self._storage_pool_properties = None
        self._storage_pool_id = None
        self._copy_id = None
        self._copy_name = None

        if storage_pool_id:
            self._storage_pool_id = str(storage_pool_id)
        else:
            self._storage_pool_id = self._commcell_object.storage_pools.get(self._storage_pool_name).storage_pool_id

        self._STORAGE_POOL = self._commcell_object._services['GET_STORAGE_POOL'] % (self.storage_pool_id)
        self.refresh()

        self._copy_id = self._storage_pool_properties.get("storagePoolDetails", {}).get("copyInfo", {}).get(
            "StoragePolicyCopy", {}).get("copyId")
        self._copy_name = self._storage_pool_properties.get("storagePoolDetails", {}).get("copyInfo", {}).get(
            "StoragePolicyCopy", {}).get("copyName")

    def __repr__(self):
        """String representation of the instance of this class"""
        representation_string = "Storage Pool class Instance for {0}".format(self._storage_pool_name)
        return representation_string

    def _get_storage_pool_properties(self):
        """
        Gets StoragePool properties

            Raises:
                SDKException:
                    if repsonse is empty

                    if response is not success

        """
        flag, response = self._commcell_object._cvpysdk_object.make_request('GET', self._STORAGE_POOL)

        if flag:
            if response.json():
                self._storage_pool_properties = response.json()
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

    @property
    def storage_pool_name(self):
        """Treats the storage_policy_name as a read only attribute"""
        return self._storage_pool_name

    @property
    def storage_pool_id(self):
        """Treats id as a read only attribute"""
        return self._storage_pool_id

    @property
    def storage_pool_properties(self):
        """Treats the storage_pool_properties as a read only attribute"""
        return self._storage_pool_properties

    @property
    def global_policy_name(self):
        """Returns the global policy corresponding to the storage pool"""
        return self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["StoragePolicyCopy"]["storagePolicyName"]

    @property
    def copy_name(self):
        """Treats copy name as a read only attribute"""
        return self._copy_name

    @property
    def copy_id(self):
        """Treats copy ID as a read only attribute"""
        return self._copy_id

    @property
    def storage_pool_type(self):
        """Treats storage type as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["storagePoolType"]

    @property
    def storage_type(self):
        """Treats storage type as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["storageType"]

    @property
    def storage_vendor(self):
        """Treats library vendor like cloud storage provider as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["libraryVendorId"]

    @property
    def is_worm_storage_lock_enabled(self):
        """Treats is worm enabled as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["isWormStorage"]

    @property
    def is_object_level_worm_lock_enabled(self):
        """Treats is object WORM enabled as a read only attribute"""
        worm_flag = int(self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["wormStorageFlag"])
        return worm_flag & WORMLockType.OBJECT == WORMLockType.OBJECT

    @property
    def is_bucket_level_worm_lock_enabled(self):
        """Treats is bucket WORM enabled as a read only attribute"""
        worm_flag = int(self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["wormStorageFlag"])
        return worm_flag & WORMLockType.BUCKET == WORMLockType.BUCKET

    @property
    def is_compliance_lock_enabled(self):
        """Treats is compliance lock enabled as a read only attribute"""
        return self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["copyFlags"]["wormCopy"] == 1

    def get_copy(self):
        """ Returns the StoragePolicyCopy object of Storage Pool copy"""
        return StoragePolicyCopy(self._commcell_object, self.storage_pool_name, self.copy_name)

    def enable_compliance_lock(self):
        """ Enables compliance lock on Storage Pool Copy """
        self.get_copy().enable_compliance_lock()
        self.refresh()

    def enable_worm_storage_lock(self, retain_days):
        """
        Enable storage WORM lock on storage pool

        Args:
            retain_days    (int)   -- number of days of retention on WORM copy.

        Raises:
            SDKException:
                if response is not success.

                if reponse is empty.
        """

        request_json = {
            "storagePolicyCopyInfo": {
                "copyFlags": {
                    "wormCopy": 1
                },
                "retentionRules": {
                    "retainBackupDataForDays": retain_days
                }
            },
            "isWormStorage": True,
            "forceCopyToFollowPoolRetention": True
        }

        _STORAGE_POOL_COPY = self._commcell_object._services['STORAGE_POLICY_COPY'] % (
            self._storage_pool_id, str(self.copy_id))
        flag, response = self._commcell_object._cvpysdk_object.make_request('PUT', _STORAGE_POOL_COPY, request_json)

        if flag:
            if response.json():
                response = response.json()
                if "error" in response and response.get("error", {}).get("errorCode") != 0:
                    error_message = response.get("error", {}).get("errorMessage")
                    raise SDKException('Response', '102', error_message)
                else:
                    self.refresh()
            else:
                raise SDKException('Response', '101')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

    def hyperscale_add_nodes(self, media_agents):
        """
        Add 3 new nodes to an existing storage pool

        args:
            media_agents      (List)   -- List of 3 media agents with name's(str)
                                            or instance of media agent's(object)

            Example: ["ma1","ma2","ma3"]

        Raises:
                SDKException:
                    if add nodes to an existing storage pool fails
        """
        if not isinstance(media_agents, list):
            raise SDKException('Storage', '101')

        mediagent_obj = []
        for media_agent in media_agents:
            if isinstance(media_agent, MediaAgent):
                mediagent_obj.append(media_agent)
            elif isinstance(media_agent, str):
                mediagent_obj.append(self._commcell_object.media_agents.get(media_agent))
            else:
                raise SDKException('Storage', '103')

        if len(mediagent_obj) <= 2:
            raise SDKException('Storage', '102', "Minimum 3 MediaAgents required")

        request_json = {
            "scaleoutOperationType": 2,
            "StoragePolicy": {
                "storagePolicyName": "{0}".format(self.storage_pool_name),
            },
            "storage": [
                {
                    "mediaAgent": {
                        "displayName": "{0}".format(mediagent_obj[0].media_agent_id),
                        "mediaAgentName": "{0}".format(mediagent_obj[0].media_agent_name)
                    }
                },
                {
                    "mediaAgent": {
                        "displayName": "{0}".format(mediagent_obj[1].media_agent_id),
                        "mediaAgentName": "{0}".format(mediagent_obj[1].media_agent_name)
                    }
                },
                {
                    "mediaAgent": {
                        "displayName": "{0}".format(mediagent_obj[2].media_agent_id),
                        "mediaAgentName": "{0}".format(mediagent_obj[2].media_agent_name)
                    }
                }
            ],
            "scaleoutConfiguration": {
                "configurationType": 1
            }
        }

        self._edit_storage_pool_api = self._commcell_object._services[
            'EDIT_STORAGE_POOL']

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._edit_storage_pool_api, request_json
        )

        if flag:
            if response.json():
                error_code = response.json()['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['errorMessage']
                    o_str = 'Failed to add nodes to storage pool\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()

    def hyperscale_reconfigure_storage_pool(self, storage_pool_name):
        """
        Reconfigures storage pool, for any failure during creation and expansion

        args:
          storage_pool_name (string) -- Name of the storage pools to reconfigure
        Raises:
                SDKException:
                    if reconfigure fails
        """
        if not isinstance(storage_pool_name, str):
            raise SDKException('Storage', '101')

        request_json = {

            "scaleoutOperationType": 4,
            "StoragePolicy":
                {
                    "storagePolicyName": "{0}".format(storage_pool_name),
                    "storagePolicyId": int("{0}".format(self.storage_pool_id))

                }
        }

        self._edit_storage_pool_api = self._commcell_object._services[
            'EDIT_STORAGE_POOL']

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._edit_storage_pool_api, request_json
        )

        if flag:
            if response.json():
                error_code = response.json()['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['errorMessage']
                    o_str = 'Failed to reconfigure storage pool\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()

    def hyperscale_replace_disk(self, disk_id, media_agent, storage_pool_name):
        """
              Replace disk action, over a media agent which is part of storage pool
               args:
                    disk_id (int) --> disk id for the disk to replace
                    media_agent (string/object) --> media agent name/ object
                    storage_pool_name (string) --> Name of the storage pools for replacemnet of disk
               Raises:
                       SDKException:
                           if replace fails
               """
        if isinstance(disk_id, str):
            disk_id = int(disk_id)
        elif not isinstance(disk_id, int):
            raise SDKException('Storage', '101')

        media_agent_obj = None
        if isinstance(media_agent, str):
            media_agent_obj = self._commcell_object.media_agents.get(media_agent)
        elif isinstance(media_agent, MediaAgent):
            media_agent_obj = media_agent
        else:
            raise SDKException('Storage', '103')

        if not isinstance(storage_pool_name, str):
            raise SDKException('Storage', '101')

        request_json = {

            "driveId": int("{0}".format(disk_id)),
            "operationType": 1,
            "mediaAgent": {
                "_type_": 11,
                "mediaAgentId": int("{0}".format(media_agent_obj.media_agent_id)),
                "mediaAgentName": "{0}".format(media_agent_obj.media_agent_name)
            },
            "scaleoutStoragePool": {
                "_type_": 160,
                "storagePoolId": int("{0}".format(self.storage_pool_id)),
                "storagePoolName": "{0}".format(self.storage_pool_name)
            }
        }

        self._replace_disk_storage_pool_api = self._commcell_object._services[
            'REPLACE_DISK_STORAGE_POOL']

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._replace_disk_storage_pool_api, request_json
        )

        if flag:
            if response.json():
                error_code = response.json()['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['errorMessage']
                    o_str = 'Failed to replace disk\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()

    def refresh(self):
        """Refreshes propery of the class object"""
        self._get_storage_pool_properties()

    def update_security_associations(self, associations_list, isUser=True, request_type=None, externalGroup=False):
        """
        Adds the security association on the storage pool object

        Args:
            associations_list   (list)  --  list of users to be associated
                Example:
                    associations_list = [
                        {
                            'user_name': user1,
                            'role_name': role1
                        },
                        {
                            'user_name': user2,
                            'role_name': role2
                        }
                    ]

            isUser (bool)           --    True or False. set isUser = False, If associations_list made up of user groups
            request_type (str)      --    eg : 'OVERWRITE' or 'UPDATE' or 'DELETE', Default will be OVERWRITE operation
            externalGroup (bool)    --    True or False, set externalGroup = True. If Security associations is being done on External User Groups

        Raises:
            SDKException:
                if association is not of List type
        """
        if not isinstance(associations_list, list):
            raise SDKException('StoragePool', '101')

        SecurityAssociation(self._commcell_object, self)._add_security_association(associations_list,
                                                                                   user=isUser,
                                                                                   request_type=request_type,
                                                                                   externalGroup=externalGroup)

Instance variables

var copy_id

Treats copy ID as a read only attribute

Expand source code Browse git
@property
def copy_id(self):
    """Treats copy ID as a read only attribute"""
    return self._copy_id
var copy_name

Treats copy name as a read only attribute

Expand source code Browse git
@property
def copy_name(self):
    """Treats copy name as a read only attribute"""
    return self._copy_name
var global_policy_name

Returns the global policy corresponding to the storage pool

Expand source code Browse git
@property
def global_policy_name(self):
    """Returns the global policy corresponding to the storage pool"""
    return self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["StoragePolicyCopy"]["storagePolicyName"]
var is_bucket_level_worm_lock_enabled

Treats is bucket WORM enabled as a read only attribute

Expand source code Browse git
@property
def is_bucket_level_worm_lock_enabled(self):
    """Treats is bucket WORM enabled as a read only attribute"""
    worm_flag = int(self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["wormStorageFlag"])
    return worm_flag & WORMLockType.BUCKET == WORMLockType.BUCKET
var is_compliance_lock_enabled

Treats is compliance lock enabled as a read only attribute

Expand source code Browse git
@property
def is_compliance_lock_enabled(self):
    """Treats is compliance lock enabled as a read only attribute"""
    return self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["copyFlags"]["wormCopy"] == 1
var is_object_level_worm_lock_enabled

Treats is object WORM enabled as a read only attribute

Expand source code Browse git
@property
def is_object_level_worm_lock_enabled(self):
    """Treats is object WORM enabled as a read only attribute"""
    worm_flag = int(self._storage_pool_properties["storagePoolDetails"]["copyInfo"]["wormStorageFlag"])
    return worm_flag & WORMLockType.OBJECT == WORMLockType.OBJECT
var is_worm_storage_lock_enabled

Treats is worm enabled as a read only attribute

Expand source code Browse git
@property
def is_worm_storage_lock_enabled(self):
    """Treats is worm enabled as a read only attribute"""
    return self._storage_pool_properties["storagePoolDetails"]["isWormStorage"]
var storage_pool_id

Treats id as a read only attribute

Expand source code Browse git
@property
def storage_pool_id(self):
    """Treats id as a read only attribute"""
    return self._storage_pool_id
var storage_pool_name

Treats the storage_policy_name as a read only attribute

Expand source code Browse git
@property
def storage_pool_name(self):
    """Treats the storage_policy_name as a read only attribute"""
    return self._storage_pool_name
var storage_pool_properties

Treats the storage_pool_properties as a read only attribute

Expand source code Browse git
@property
def storage_pool_properties(self):
    """Treats the storage_pool_properties as a read only attribute"""
    return self._storage_pool_properties
var storage_pool_type

Treats storage type as a read only attribute

Expand source code Browse git
@property
def storage_pool_type(self):
    """Treats storage type as a read only attribute"""
    return self._storage_pool_properties["storagePoolDetails"]["storagePoolType"]
var storage_type

Treats storage type as a read only attribute

Expand source code Browse git
@property
def storage_type(self):
    """Treats storage type as a read only attribute"""
    return self._storage_pool_properties["storagePoolDetails"]["storageType"]
var storage_vendor

Treats library vendor like cloud storage provider as a read only attribute

Expand source code Browse git
@property
def storage_vendor(self):
    """Treats library vendor like cloud storage provider as a read only attribute"""
    return self._storage_pool_properties["storagePoolDetails"]["libraryVendorId"]

Methods

def enable_compliance_lock(self)

Enables compliance lock on Storage Pool Copy

Expand source code Browse git
def enable_compliance_lock(self):
    """ Enables compliance lock on Storage Pool Copy """
    self.get_copy().enable_compliance_lock()
    self.refresh()
def enable_worm_storage_lock(self, retain_days)

Enable storage WORM lock on storage pool

Args

retain_days (int) – number of days of retention on WORM copy.

Raises

SDKException: if response is not success.

if reponse is empty.
Expand source code Browse git
def enable_worm_storage_lock(self, retain_days):
    """
    Enable storage WORM lock on storage pool

    Args:
        retain_days    (int)   -- number of days of retention on WORM copy.

    Raises:
        SDKException:
            if response is not success.

            if reponse is empty.
    """

    request_json = {
        "storagePolicyCopyInfo": {
            "copyFlags": {
                "wormCopy": 1
            },
            "retentionRules": {
                "retainBackupDataForDays": retain_days
            }
        },
        "isWormStorage": True,
        "forceCopyToFollowPoolRetention": True
    }

    _STORAGE_POOL_COPY = self._commcell_object._services['STORAGE_POLICY_COPY'] % (
        self._storage_pool_id, str(self.copy_id))
    flag, response = self._commcell_object._cvpysdk_object.make_request('PUT', _STORAGE_POOL_COPY, request_json)

    if flag:
        if response.json():
            response = response.json()
            if "error" in response and response.get("error", {}).get("errorCode") != 0:
                error_message = response.get("error", {}).get("errorMessage")
                raise SDKException('Response', '102', error_message)
            else:
                self.refresh()
        else:
            raise SDKException('Response', '101')
    else:
        response_string = self._commcell_object._update_response_(response.text)
        raise SDKException('Response', '101', response_string)
def get_copy(self)

Returns the StoragePolicyCopy object of Storage Pool copy

Expand source code Browse git
def get_copy(self):
    """ Returns the StoragePolicyCopy object of Storage Pool copy"""
    return StoragePolicyCopy(self._commcell_object, self.storage_pool_name, self.copy_name)
def hyperscale_add_nodes(self, media_agents)

Add 3 new nodes to an existing storage pool

args: media_agents (List) – List of 3 media agents with name's(str) or instance of media agent's(object)

Example: ["ma1","ma2","ma3"]

Raises

SDKException: if add nodes to an existing storage pool fails

Expand source code Browse git
def hyperscale_add_nodes(self, media_agents):
    """
    Add 3 new nodes to an existing storage pool

    args:
        media_agents      (List)   -- List of 3 media agents with name's(str)
                                        or instance of media agent's(object)

        Example: ["ma1","ma2","ma3"]

    Raises:
            SDKException:
                if add nodes to an existing storage pool fails
    """
    if not isinstance(media_agents, list):
        raise SDKException('Storage', '101')

    mediagent_obj = []
    for media_agent in media_agents:
        if isinstance(media_agent, MediaAgent):
            mediagent_obj.append(media_agent)
        elif isinstance(media_agent, str):
            mediagent_obj.append(self._commcell_object.media_agents.get(media_agent))
        else:
            raise SDKException('Storage', '103')

    if len(mediagent_obj) <= 2:
        raise SDKException('Storage', '102', "Minimum 3 MediaAgents required")

    request_json = {
        "scaleoutOperationType": 2,
        "StoragePolicy": {
            "storagePolicyName": "{0}".format(self.storage_pool_name),
        },
        "storage": [
            {
                "mediaAgent": {
                    "displayName": "{0}".format(mediagent_obj[0].media_agent_id),
                    "mediaAgentName": "{0}".format(mediagent_obj[0].media_agent_name)
                }
            },
            {
                "mediaAgent": {
                    "displayName": "{0}".format(mediagent_obj[1].media_agent_id),
                    "mediaAgentName": "{0}".format(mediagent_obj[1].media_agent_name)
                }
            },
            {
                "mediaAgent": {
                    "displayName": "{0}".format(mediagent_obj[2].media_agent_id),
                    "mediaAgentName": "{0}".format(mediagent_obj[2].media_agent_name)
                }
            }
        ],
        "scaleoutConfiguration": {
            "configurationType": 1
        }
    }

    self._edit_storage_pool_api = self._commcell_object._services[
        'EDIT_STORAGE_POOL']

    flag, response = self._commcell_object._cvpysdk_object.make_request(
        'POST', self._edit_storage_pool_api, request_json
    )

    if flag:
        if response.json():
            error_code = response.json()['errorCode']

            if int(error_code) != 0:
                error_message = response.json()['errorMessage']
                o_str = 'Failed to add nodes to storage pool\nError: "{0}"'

                raise SDKException('StoragePool', '102', o_str.format(error_message))
        else:
            raise SDKException('Response', '102')
    else:
        response_string = self._commcell_object._update_response_(response.text)
        raise SDKException('Response', '101', response_string)

    self.refresh()
def hyperscale_reconfigure_storage_pool(self, storage_pool_name)

Reconfigures storage pool, for any failure during creation and expansion

args: storage_pool_name (string) – Name of the storage pools to reconfigure

Raises

SDKException: if reconfigure fails

Expand source code Browse git
def hyperscale_reconfigure_storage_pool(self, storage_pool_name):
    """
    Reconfigures storage pool, for any failure during creation and expansion

    args:
      storage_pool_name (string) -- Name of the storage pools to reconfigure
    Raises:
            SDKException:
                if reconfigure fails
    """
    if not isinstance(storage_pool_name, str):
        raise SDKException('Storage', '101')

    request_json = {

        "scaleoutOperationType": 4,
        "StoragePolicy":
            {
                "storagePolicyName": "{0}".format(storage_pool_name),
                "storagePolicyId": int("{0}".format(self.storage_pool_id))

            }
    }

    self._edit_storage_pool_api = self._commcell_object._services[
        'EDIT_STORAGE_POOL']

    flag, response = self._commcell_object._cvpysdk_object.make_request(
        'POST', self._edit_storage_pool_api, request_json
    )

    if flag:
        if response.json():
            error_code = response.json()['errorCode']

            if int(error_code) != 0:
                error_message = response.json()['errorMessage']
                o_str = 'Failed to reconfigure storage pool\nError: "{0}"'

                raise SDKException('StoragePool', '102', o_str.format(error_message))
        else:
            raise SDKException('Response', '102')
    else:
        response_string = self._commcell_object._update_response_(response.text)
        raise SDKException('Response', '101', response_string)

    self.refresh()
def hyperscale_replace_disk(self, disk_id, media_agent, storage_pool_name)

Replace disk action, over a media agent which is part of storage pool args: disk_id (int) –> disk id for the disk to replace media_agent (string/object) –> media agent name/ object storage_pool_name (string) –> Name of the storage pools for replacemnet of disk Raises: SDKException: if replace fails

Expand source code Browse git
def hyperscale_replace_disk(self, disk_id, media_agent, storage_pool_name):
    """
          Replace disk action, over a media agent which is part of storage pool
           args:
                disk_id (int) --> disk id for the disk to replace
                media_agent (string/object) --> media agent name/ object
                storage_pool_name (string) --> Name of the storage pools for replacemnet of disk
           Raises:
                   SDKException:
                       if replace fails
           """
    if isinstance(disk_id, str):
        disk_id = int(disk_id)
    elif not isinstance(disk_id, int):
        raise SDKException('Storage', '101')

    media_agent_obj = None
    if isinstance(media_agent, str):
        media_agent_obj = self._commcell_object.media_agents.get(media_agent)
    elif isinstance(media_agent, MediaAgent):
        media_agent_obj = media_agent
    else:
        raise SDKException('Storage', '103')

    if not isinstance(storage_pool_name, str):
        raise SDKException('Storage', '101')

    request_json = {

        "driveId": int("{0}".format(disk_id)),
        "operationType": 1,
        "mediaAgent": {
            "_type_": 11,
            "mediaAgentId": int("{0}".format(media_agent_obj.media_agent_id)),
            "mediaAgentName": "{0}".format(media_agent_obj.media_agent_name)
        },
        "scaleoutStoragePool": {
            "_type_": 160,
            "storagePoolId": int("{0}".format(self.storage_pool_id)),
            "storagePoolName": "{0}".format(self.storage_pool_name)
        }
    }

    self._replace_disk_storage_pool_api = self._commcell_object._services[
        'REPLACE_DISK_STORAGE_POOL']

    flag, response = self._commcell_object._cvpysdk_object.make_request(
        'POST', self._replace_disk_storage_pool_api, request_json
    )

    if flag:
        if response.json():
            error_code = response.json()['errorCode']

            if int(error_code) != 0:
                error_message = response.json()['errorMessage']
                o_str = 'Failed to replace disk\nError: "{0}"'

                raise SDKException('StoragePool', '102', o_str.format(error_message))
        else:
            raise SDKException('Response', '102')
    else:
        response_string = self._commcell_object._update_response_(response.text)
        raise SDKException('Response', '101', response_string)

    self.refresh()
def refresh(self)

Refreshes propery of the class object

Expand source code Browse git
def refresh(self):
    """Refreshes propery of the class object"""
    self._get_storage_pool_properties()
def update_security_associations(self, associations_list, isUser=True, request_type=None, externalGroup=False)

Adds the security association on the storage pool object

Args

associations_list (list) – list of users to be associated Example: associations_list = [ { 'user_name': user1, 'role_name': role1 }, { 'user_name': user2, 'role_name': role2 } ]

isUser (bool) – True or False. set isUser = False, If associations_list made up of user groups request_type (str) – eg : 'OVERWRITE' or 'UPDATE' or 'DELETE', Default will be OVERWRITE operation externalGroup (bool) – True or False, set externalGroup = True. If Security associations is being done on External User Groups

Raises

SDKException: if association is not of List type

Expand source code Browse git
def update_security_associations(self, associations_list, isUser=True, request_type=None, externalGroup=False):
    """
    Adds the security association on the storage pool object

    Args:
        associations_list   (list)  --  list of users to be associated
            Example:
                associations_list = [
                    {
                        'user_name': user1,
                        'role_name': role1
                    },
                    {
                        'user_name': user2,
                        'role_name': role2
                    }
                ]

        isUser (bool)           --    True or False. set isUser = False, If associations_list made up of user groups
        request_type (str)      --    eg : 'OVERWRITE' or 'UPDATE' or 'DELETE', Default will be OVERWRITE operation
        externalGroup (bool)    --    True or False, set externalGroup = True. If Security associations is being done on External User Groups

    Raises:
        SDKException:
            if association is not of List type
    """
    if not isinstance(associations_list, list):
        raise SDKException('StoragePool', '101')

    SecurityAssociation(self._commcell_object, self)._add_security_association(associations_list,
                                                                               user=isUser,
                                                                               request_type=request_type,
                                                                               externalGroup=externalGroup)
class StoragePoolType (value, names=None, *, module=None, qualname=None, type=None, start=1)

Class IntEnum to represent different storage pool types

Expand source code Browse git
class StoragePoolType(IntEnum):
    """Class IntEnum to represent different storage pool types"""
    DEDUPLICATION = 1,
    SECONDARY_COPY = 2,
    NON_DEDUPLICATION = 3,
    SCALE_OUT = 4

Ancestors

  • enum.IntEnum
  • builtins.int
  • enum.Enum

Class variables

var DEDUPLICATION
var NON_DEDUPLICATION
var SCALE_OUT
var SECONDARY_COPY
class StoragePools (commcell_object)

Class for doing operations on Storage Pools, like get storage poo ID.

Initializes instance of the StoragePools class to perform operations on a storage pool.

Args

commcell_object (object) – instance of the Commcell class

Returns

object - instance of the StoragePools class

Expand source code Browse git
class StoragePools:
    """Class for doing operations on Storage Pools, like get storage poo ID."""

    def __init__(self, commcell_object):
        """Initializes instance of the StoragePools class to perform operations on a storage pool.

            Args:
                commcell_object     (object)    --  instance of the Commcell class

            Returns:
                object  -   instance of the StoragePools class

        """
        self._commcell_object = commcell_object

        self._cvpysdk_object = commcell_object._cvpysdk_object
        self._services = commcell_object._services
        self._update_response_ = commcell_object._update_response_
        self._add_storage_pool_api = self._services['ADD_STORAGE_POOL']

        self._storage_pools_api = self._services['STORAGE_POOL']

        self._metallic_storage_api = self._services['GET_METALLIC_STORAGE_DETAILS']
        self.__get_agp_storage_api = self._services['GET_AGP_STORAGE']
        self._storage_pools = None

        self.refresh()

    def __str__(self):
        """Representation string consisting of all storage pools present in the Commcell.

            Returns:
                str     -   string of all the storage pools associated with the commcell

        """
        representation_string = '{:^5}\t{:^40}\n\n'.format('S. No.', 'Storage Pool')

        for index, storage_pool in enumerate(self._storage_pools):
            sub_str = '{:^5}\t{:40}\n'.format(index + 1, storage_pool)
            representation_string += sub_str

        return representation_string.strip()

    def __repr__(self):
        """Returns the string representation of an instance of this class."""
        return "StoragePools class instance for Commcell"

    def __len__(self):
        """Returns the number of the storage pools added to the Commcell."""
        return len(self.all_storage_pools)

    def __getitem__(self, value):
        """Returns the name of the storage pool for the given storage pool ID or
            the details of the storage pool for given storage pool Name.

            Args:
                value   (str / int)     --  Name or ID of the storage pool

            Returns:
                str     -   name of the storage pool, if the storage pool id was given

                dict    -   dict of details of the storage pool, if storage pool name was given

            Raises:
                IndexError:
                    no storage pool exists with the given Name / Id

        """
        value = str(value)

        if value in self.all_storage_pools:
            return self.all_storage_pools[value]
        else:
            try:
                return list(filter(lambda x: x[1]['id'] == value, self.all_storage_pools.items()))[0][0]
            except IndexError:
                raise IndexError('No storage pool exists with the given Name / Id')

    def _get_storage_pools(self):
        """Gets all the storage pools associated with the Commcell environment.

            Returns:
                dict    -   consists of all storage pools added to the commcell

                    {
                        "storage_pool1_name": storage_pool1_id,

                        "storage_pool2_name": storage_pool2_id
                    }

            Raises:
                SDKException:
                    if response is empty

                    if response is not success

        """
        headers = self._commcell_object._headers.copy()
        headers['Accept'] = 'application/xml'

        flag, response = self._cvpysdk_object.make_request(
            'GET', self._storage_pools_api, headers=headers
        )

        if flag:
            storage_pools = {}

            response = xmltodict.parse(response.text)['Api_GetStoragePoolListResp']

            if response is None or response.get('storagePoolList') is None:
                storage_pool_list = []
            else:
                storage_pool_list = response['storagePoolList']

            if not isinstance(storage_pool_list, list):
                storage_pool_list = [storage_pool_list]

            if response:
                for pool in storage_pool_list:
                    name = pool['storagePoolEntity']['@storagePoolName'].lower()
                    storage_pool_id = pool['storagePoolEntity']['@storagePoolId']

                    storage_pools[name] = storage_pool_id

                return storage_pools
        else:
            response_string = self._update_response_(response.text)
            raise SDKException('Response', '101', response_string)
    
    def get_storage_pools_for_a_company(self, company_id, storage_type: StorageType = None):
        """Gets all the storage pools associated with the Commcell environment.

            Args:
                company_id - id of the company for which the associated storge pools are to be fetched

            Returns:
                dict    -   consists of all storage pools added to the commcell

                    {
                        "storage_pool1_name": storage_pool1_id,

                        "storage_pool2_name": storage_pool2_id
                    }

            Raises:
                SDKException:
                    if response is empty

                    if response is not success

        """
        headers = self._commcell_object._headers.copy()
        headers['Accept'] = 'application/json'
        headers['onlygetcompanyownedentities'] = '1'
        headers['operatorcompanyid'] = f'{company_id}'

        flag, response = self._cvpysdk_object.make_request(
            'GET', self._storage_pools_api, headers=headers
        )

        if flag:
            storage_pools = {}
            response = response.json()
            if response is None or response.get('storagePoolList') is None:
                storage_pool_list = []
            else:
                storage_pool_list = response['storagePoolList']
            if not isinstance(storage_pool_list, list):
                storage_pool_list = [storage_pool_list]
            if response:
                for pool in storage_pool_list:
                    if storage_type and pool['storageType'] != storage_type:
                        continue
                    # skip agp pools for cloud storage type
                    if storage_type == StorageType.CLOUD and 401 <= pool['libraryVendorType'] <= 499:
                        continue
                    name = pool['storagePoolEntity']['storagePoolName']
                    storage_pool_id = pool['storagePoolEntity']['storagePoolId']

                    storage_pools[name] = storage_pool_id

            return storage_pools
        else:
            response_string = self._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

    @property
    def all_storage_pools(self):
        """Returns dict of all the storage pools on this commcell

            dict    -   consists of all storage pools added to the commcell

                {

                    "storage_pool1_name": storage_pool1_id,

                    "storage_pool2_name": storage_pool2_id
                }

        """
        return self._storage_pools

    def has_storage_pool(self, name):
        """Checks if a storage pool exists in the Commcell with the input storage pool name.

            Args:
                name    (str)   --  name of the storage pool

            Returns:
                bool    -   boolean output whether the storage pool exists in the commcell or not

        """
        return self._storage_pools and name.lower() in self._storage_pools

    def get(self, name):
        """Returns the id of the storage pool for the given storage pool name.

            Args:
                name    (str)   --  name of the storage pool to get the id of

            Returns:
                str     -   id of the storage pool for the given storage pool name

            Raises:
                SDKException:
                    if no storage pool exists with the given name

        """
        self.refresh()
        name = name.lower()

        if self.has_storage_pool(name):
            return StoragePool(self._commcell_object, name, storage_pool_id=self._storage_pools[name])
        else:
            raise SDKException('StoragePool', '103')

    def hyperscale_create_storage_pool(self, storage_pool_name, media_agents):
        """
            Create new storage pool for hyperscale
            Args:
                storage_pool_name (string) -- Name of the storage pools to create

                media_agents      (List)   -- List of 3 media agents with name's(str)
                                                or instance of media agent's(object)

                Example: ["ma1","ma2","ma3"]

            Return:
                 flag, response -- response returned by the REST API call
        """

        if not isinstance(media_agents, list):
            raise SDKException('Storage', '101')
        if not isinstance(storage_pool_name, str):
            raise SDKException('Storage', '101')

        mediagent_obj = []
        for media_agent in media_agents:
            if isinstance(media_agent, MediaAgent):
                mediagent_obj.append(media_agent)
            elif isinstance(media_agent, str):
                mediagent_obj.append(self._commcell_object.media_agents.get(media_agent))
            else:
                raise SDKException('Storage', '103')
        if len(mediagent_obj) <= 2:
            raise SDKException('Storage', '102', "minimum 3 media agents are required")

        request_xml = """<App_CreateStoragePolicyReq storagePolicyName="{0}" copyName="{0}_Primary" type="1"
                                     numberOfCopies="1">
                                    <storagePolicyCopyInfo>
                                        <storagePolicyFlags scaleOutStoragePolicy="1"/>
                                    </storagePolicyCopyInfo>
                                    <storage>
                                        <mediaAgent mediaAgentId="{4}" mediaAgentName="{1}" displayName="{1}"/>
                                    </storage>
                                    <storage>
                                        <mediaAgent mediaAgentId="{5}" mediaAgentName="{2}" displayName="{2}"/>
                                    </storage>
                                    <storage>
                                        <mediaAgent mediaAgentId="{6}" mediaAgentName="{3}" displayName="{3}"/>
                                    </storage>
                                    <scaleoutConfiguration configurationType="1"/>
                                </App_CreateStoragePolicyReq>
                                """.format(storage_pool_name, mediagent_obj[0].media_agent_name,
                                           mediagent_obj[1].media_agent_name, mediagent_obj[2].media_agent_name,
                                           mediagent_obj[0].media_agent_id, mediagent_obj[1].media_agent_id,
                                           mediagent_obj[2].media_agent_id)

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._add_storage_pool_api, request_xml
        )
        if flag:
            if response.json():
                error_code = response.json()['error']['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['error']['errorMessage']
                    o_str = 'Failed to create storage pool\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()
        return self.get(storage_pool_name)

    def add_air_gap_protect(self, storage_pool_name, media_agent, storage_type, storage_class, region_name,
                            ddb_ma=None, dedup_path=None):
        """
            Adds a new air gap protect storage pool to commcell

                Args:
                    storage_pool_name   (str)       --  name of new storage pool to add

                    media_agent         (str/object)--  name or instance of media agent

                    storage_type        (str)        -- name of the cloud vendor (str, eg - "Microsoft Azure storage") (same as UI)

                    storage_class       (str)        -- storage class (str, eg - "Hot","Cool") (same as UI)

                    region_name (str)      --  name of the geographical region for storage (same as UI)

                    ddb_ma              (list<str/object>/str/object)   --  list of (name of name or instance)
                                                                            or name or instance of dedupe media agent

                    dedup_path          (list<str>/str)       --  list of paths or path where the DDB should be stored

                Returns:
                    StoragePool object if creation is successful

                Raises:
                    SDKException, if invalid parameters provided

        """
        license_type_dict = StoragePoolConstants.AIR_GAP_PROTECT_STORAGE_TYPES
        error_message = ""
        if storage_type.upper() in license_type_dict:
            available_storage_classes = license_type_dict[storage_type.upper()]
            if storage_class.upper() in available_storage_classes:
                vendor_id = available_storage_classes[storage_class.upper()]["vendorId"]
                display_vendor_id = available_storage_classes[storage_class.upper()]["displayVendorId"]
            else:
                error_message += f"Invalid storage class provided. Valid storage class {list(available_storage_classes.keys())}"
        else:
            error_message += f"  Invalid storage type provided. {list(license_type_dict.keys())}"

        if error_message:
            raise SDKException('Storage', '101', error_message)

        region = None
        available_regions = []

        #  API call to fetch the region name - sourced directly from the vendor
        flag, response = self._commcell_object._cvpysdk_object.make_request('GET', self._metallic_storage_api)
        if flag:
            if response.json():
                if "storageInformation" in response.json():
                    for storage_info in response.json()["storageInformation"]:
                        if (int(storage_info["vendorId"]) == int(vendor_id)) and (int(storage_info["displayVendorId"]) == int(display_vendor_id)):
                            for region_dict in storage_info["region"]:
                                available_regions.append(region_dict["displayName"])
                                if region_dict["displayName"] == region_name:
                                    region = region_dict["regionName"]
                                    break

                        if region:
                            break

                    if region is None:
                        if not available_regions:
                            raise SDKException('Storage', '101',
                                               f"Active license is required to configure {storage_type} - {storage_class} Air Gap Protect storage")
                        else:
                            raise SDKException('Storage', '101',
                                               f"Invalid region: {region_name} ,\nValid regions: {available_regions}")
                else:
                    raise SDKException('Storage', '101', "Unexpected response returned while fetching Air Gap Protect storage details")
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        # cloud server type for air gap protect is 400
        cloud_server_type = 400

        return self.add(storage_pool_name=storage_pool_name, mountpath=None, media_agent=media_agent, ddb_ma=ddb_ma,
                        dedup_path=dedup_path, cloud_server_type=cloud_server_type, region=region, vendor_id=vendor_id,
                        display_vendor_id=display_vendor_id)
        
    def get_air_gap_protect(self, company_id = None):
        """
        Returns the list of air gap protect storage pools in the commcell.
        
        Args:
            company_id (int) -- id of the company to get the air gap protect storage pools for
                                (optional, default is None which returns all air gap protect storage pools)
        
        Returns:
            dict - dictionary of air gap protect storage pools with name as key and id as value
                
                    {
                        "storage_pool1_name": storage_pool1_id,
                        "storage_pool2_name": storage_pool2_id
                    }  
        
        Raises:
            SDKException:
                if response is empty

                if response is not success
        """
        headers = self._commcell_object._headers.copy()
        headers['Accept'] = 'application/json'
        if company_id:
            headers['onlygetcompanyownedentities'] = '1'
            headers['operatorcompanyid'] = f'{company_id}'

        flag, response = self._cvpysdk_object.make_request(
            'GET', self.__get_agp_storage_api, headers=headers
        )

        if flag:
            storage_pools = {}
            response = response.json()
            if response is None or response.get('cloudStorage') is None:
                storage_pool_list = []
            else:
                storage_pool_list = response['cloudStorage']
            if not isinstance(storage_pool_list, list):
                storage_pool_list = [storage_pool_list]
            if response:
                for pool in storage_pool_list:
                    name = pool['name']
                    storage_pool_id = pool['id']

                    storage_pools[name] = storage_pool_id

            return storage_pools
        else:
            response_string = self._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

    def add(self, storage_pool_name, mountpath, media_agent, ddb_ma=None, dedup_path=None, **kwargs):
        """
        Adds a new storage pool to commcell

        Args:
            storage_pool_name   (str)       --  name of new storage pool to add

            mountpath           (str)       --  mount path for the storage pool

            media_agent         (str/object)--  name or instance of media agent

            ddb_ma              (list<str/object>/str/object)   --  list of (name of name or instance)
                                                                        or name or instance of dedupe media agent

            dedup_path          (list<str>/str)       --  list of paths or path where the DDB should be stored

            **kwargs:
                username        (str)       --  username to access the mountpath

                password        (str)       --  password to access the mountpath

                credential_name (str)       --  name of the credential as in credential manager

                cloud_server_type (int)     --  cloud server type of the cloud vendor (required)

                region (str)                --  name of geographical region for storage (required for air gap protect)

                vendor_id (int)             -- id for the cloud_vendor (eg - 3 for azure) (required for air gap protect pool)

                display_vendor_id (int)     -- storage Class id for that vendor (eg - 401 for azure hot) (required for air gap protect pool)

                region_id        (int)      --  Cloud Hypervisor specific region ID

                tape_storage (boolean)      -- if library passed is tape library. 

        Returns:
            StoragePool object if creation is successful

        Raises:
            Exception if creation is unsuccessful
        """
        username = kwargs.get('username', None)
        password = kwargs.get('password', None)
        credential_name = kwargs.get('credential_name', None)
        cloud_server_type = kwargs.get('cloud_server_type', None)
        library_name = kwargs.get('library_name', None)
        tape_storage = False

        region = kwargs.get('region', None)
        vendor_id = kwargs.get('vendor_id', None)
        display_vendor_id = kwargs.get('display_vendor_id', None)
        region_id = kwargs.get('region_id', None)

        if library_name:
            library_object = self._commcell_object.disk_libraries.get(library_name)
            library_type = library_object.library_properties.get('libraryType', None)
            tape_storage = True if library_type == 1 else tape_storage


        if ((ddb_ma is not None and not (isinstance(dedup_path, str) or isinstance(dedup_path, list))) or
                not (isinstance(storage_pool_name, str) or not isinstance(mountpath, str))):
            raise SDKException('Storage', '101')

        if isinstance(media_agent, MediaAgent):
            media_agent = media_agent
        elif isinstance(media_agent, str):
            media_agent = MediaAgent(self._commcell_object, media_agent)
        else:
            raise SDKException('Storage', '103')

        if (isinstance(ddb_ma, str) or isinstance(ddb_ma, MediaAgent)) and isinstance(dedup_path, str):
            ddb_ma = [ddb_ma]
            dedup_path = [dedup_path]

        if isinstance(ddb_ma, list) and isinstance(dedup_path, list):
            if len(ddb_ma) != len(dedup_path):
                raise SDKException('Storage', '101')

        if library_name is not None and mountpath != '':
            raise SDKException('Storage', '101')

        if ddb_ma is not None and (len(ddb_ma) > 6 or len(dedup_path) > 6):
            raise SDKException('Storage', '110')

        if ddb_ma is not None:
            for i in range(len(ddb_ma)):
                if isinstance(ddb_ma[i], MediaAgent):
                    ddb_ma[i] = ddb_ma[i]
                elif isinstance(ddb_ma[i], str):
                    ddb_ma[i] = MediaAgent(self._commcell_object, ddb_ma[i])
                else:
                    raise SDKException('Storage', '103')

        request_json = {
            "storagePolicyName": storage_pool_name,
            "type": "CVA_REGULAR_SP",
            "copyName": "Primary",
            "numberOfCopies": 1,
            "storage": [
                {
                    "path": mountpath,
                    "mediaAgent": {
                        "mediaAgentId": int(media_agent.media_agent_id),
                        "mediaAgentName": media_agent.media_agent_name
                    }
                }
            ],
            "storagePolicyCopyInfo": {
                "copyType": "SYNCHRONOUS",
                "isFromGui": True,
                "active": "SET_TRUE",
                "isDefault": "SET_TRUE",
                "numberOfStreamsToCombine": 1,
                "retentionRules": {
                    "retentionFlags": {
                        "enableDataAging": "SET_TRUE"
                    },
                    "retainBackupDataForDays": -1,
                    "retainBackupDataForCycles": -1,
                    "retainArchiverDataForDays": -1
                },
                "library": {
                    "libraryId": 0,
                },
                "mediaAgent": {
                    "mediaAgentId": int(media_agent.media_agent_id),
                    "mediaAgentName": media_agent.media_agent_name
                }
            }
        }

        if cloud_server_type and int(cloud_server_type) > 0:
            request_json["storage"][0]["deviceType"] = cloud_server_type

        if region_id is not None:
            request_json["storage"][0]["metallicStorageInfo"] = {
                "region": [
                    {
                        "regionId": region_id
                    }
                ],
                "storageClass": [
                    "CONTAINER_DEFAULT"
                ],
                "replication": [
                    "NONE"
                ]
            }
            request_json["region"] = {"regionId": region_id}

        if username is not None:
            request_json["storage"][0]["credentials"] = {"userName": username}

        if password is not None:
            request_json["storage"][0]["credentials"]["password"] = b64encode(password.encode()).decode()

        if credential_name is not None:
            request_json["storage"][0]["savedCredential"] = {"credentialName": credential_name}

        if library_name is not None:
            request_json["storage"] = []
            request_json["storagePolicyCopyInfo"]["library"]["libraryName"] = library_name

        if ddb_ma is not None or dedup_path is not None:
            maInfoList = []
            for ma, path in zip(ddb_ma, dedup_path):
                maInfoList.append({
                    "mediaAgent": {
                        "mediaAgentId": int(ma.media_agent_id),
                        "mediaAgentName": ma.media_agent_name
                    },
                    "subStoreList": [
                        {
                            "accessPath": {
                                "path": path
                            },
                            "diskFreeThresholdMB": 5120,
                            "diskFreeWarningThreshholdMB": 10240
                        }]
                })

            request_json["storagePolicyCopyInfo"].update({
                "storagePolicyFlags": {
                    "blockLevelDedup": "SET_TRUE",
                    "enableGlobalDeduplication": "SET_TRUE"
                },
                "dedupeFlags": {
                    "enableDeduplication": "SET_TRUE",
                    "enableDASHFull": "SET_TRUE",
                    "hostGlobalDedupStore": "SET_TRUE"
                },
                "DDBPartitionInfo": {
                    "maInfoList": maInfoList
                }
            })
        elif tape_storage:
            request_json["storagePolicyCopyInfo"].update({
                "storagePolicyFlags": {
                    "globalAuxCopyPolicy": "SET_TRUE"
                },
                "copyFlags": {
                    "preserveEncryptionModeAsInSource": "SET_TRUE"
                },
                "extendedFlags": {
                    "globalAuxCopyPolicy": "SET_TRUE"
                }
            })
        else:
            request_json["storagePolicyCopyInfo"].update({
                "storagePolicyFlags": {
                    "globalStoragePolicy": "SET_TRUE"
                },
                "copyFlags": {
                    "preserveEncryptionModeAsInSource": "SET_TRUE"
                },
                "extendedFlags": {
                    "globalStoragePolicy": "SET_TRUE"
                }
            })

        # air gap protect storage
        if cloud_server_type == 400:
            del request_json["storage"][0]["path"]
            request_json["storage"][0]["savedCredential"] = {"credentialId": 0}

            metallic_Storage = {
                "region": [
                    {
                        "regionName": region
                    }
                ],
                "displayVendorId": display_vendor_id,
                "vendorId": vendor_id
            }
            request_json["storage"][0]["metallicStorageInfo"] = metallic_Storage

        flag, response = self._commcell_object._cvpysdk_object.make_request(
            'POST', self._add_storage_pool_api, request_json
        )

        if flag:
            if response.json():
                error_code = response.json()['error']['errorCode']

                if int(error_code) != 0:
                    error_message = response.json()['error']['errorMessage']
                    o_str = 'Failed to create storage pool\nError: "{0}"'

                    raise SDKException('StoragePool', '102', o_str.format(error_message))
            else:
                raise SDKException('Response', '102')
        else:
            response_string = self._commcell_object._update_response_(response.text)
            raise SDKException('Response', '101', response_string)

        self.refresh()
        self._commcell_object.disk_libraries.refresh()
        return self.get(storage_pool_name)

    def delete(self, storage_pool_name):
        """deletes the specified storage pool.

            Args:
                storage_pool_name (str)  --  name of the storage pool to delete

            Raises:
                SDKException:
                    if type of the storage pool name is not string

                    if failed to delete storage pool

                    if no storage pool exists with the given name

                    if response is empty

                    if response is not success

        """

        if not isinstance(storage_pool_name, str):
            raise SDKException('Storage', '101')
        else:
            storage_pool_name = storage_pool_name.lower()

            if self.has_storage_pool(storage_pool_name):
                storage_pool_id = self._storage_pools[storage_pool_name]

                delete_storage_pool = self._services['DELETE_STORAGE_POOL'] % (storage_pool_id)

                flag, response = self._cvpysdk_object.make_request('DELETE', delete_storage_pool)

                if flag:
                    error_code = response.json()['error']['errorCode']
                    if int(error_code) != 0:
                        error_message = response.json()['error']['errorMessage']
                        o_str = f'Failed to delete storage pools {storage_pool_name}'
                        o_str += '\nError: "{0}"'.format(error_message)
                        raise SDKException('Storage', '102', o_str)
                    else:
                        # initialize the storage pool again
                        # so the storage pool object has all the storage pools
                        self.refresh()
                        # as part of storage pool we might delete library so initialize the libraries again
                        self._commcell_object.disk_libraries.refresh()
                else:
                    response_string = self._update_response_(response.text)
                    raise SDKException('Response', '101', response_string)
            else:
                raise SDKException(
                    'Storage',
                    '102',
                    'No storage pool exists with name: {0}'.format(storage_pool_name)
                )
    def refresh(self):
        """Refresh the list of storage pools associated to the Commcell."""
        self._storage_pools = self._get_storage_pools()

Instance variables

var all_storage_pools

Returns dict of all the storage pools on this commcell

dict - consists of all storage pools added to the commcell

{

    "storage_pool1_name": storage_pool1_id,

    "storage_pool2_name": storage_pool2_id
}
Expand source code Browse git
@property
def all_storage_pools(self):
    """Returns dict of all the storage pools on this commcell

        dict    -   consists of all storage pools added to the commcell

            {

                "storage_pool1_name": storage_pool1_id,

                "storage_pool2_name": storage_pool2_id
            }

    """
    return self._storage_pools

Methods

def add(self, storage_pool_name, mountpath, media_agent, ddb_ma=None, dedup_path=None, **kwargs)

Adds a new storage pool to commcell

Args

storage_pool_name (str) – name of new storage pool to add

mountpath (str) – mount path for the storage pool

media_agent (str/object)– name or instance of media agent

ddb_ma (list/str/object) – list of (name of name or instance) or name or instance of dedupe media agent

dedup_path (list/str) – list of paths or path where the DDB should be stored

**kwargs: username (str) – username to access the mountpath

password        (str)       --  password to access the mountpath

credential_name (str)       --  name of the credential as in credential manager

cloud_server_type (int)     --  cloud server type of the cloud vendor (required)

region (str)                --  name of geographical region for storage (required for air gap protect)

vendor_id (int)             -- id for the cloud_vendor (eg - 3 for azure) (required for air gap protect pool)

display_vendor_id (int)     -- storage Class id for that vendor (eg - 401 for azure hot) (required for air gap protect pool)

region_id        (int)      --  Cloud Hypervisor specific region ID

tape_storage (boolean)      -- if library passed is tape library.

Returns

StoragePool object if creation is successful

Raises

Exception if creation is unsuccessful

Expand source code Browse git
def add(self, storage_pool_name, mountpath, media_agent, ddb_ma=None, dedup_path=None, **kwargs):
    """
    Adds a new storage pool to commcell

    Args:
        storage_pool_name   (str)       --  name of new storage pool to add

        mountpath           (str)       --  mount path for the storage pool

        media_agent         (str/object)--  name or instance of media agent

        ddb_ma              (list<str/object>/str/object)   --  list of (name of name or instance)
                                                                    or name or instance of dedupe media agent

        dedup_path          (list<str>/str)       --  list of paths or path where the DDB should be stored

        **kwargs:
            username        (str)       --  username to access the mountpath

            password        (str)       --  password to access the mountpath

            credential_name (str)       --  name of the credential as in credential manager

            cloud_server_type (int)     --  cloud server type of the cloud vendor (required)

            region (str)                --  name of geographical region for storage (required for air gap protect)

            vendor_id (int)             -- id for the cloud_vendor (eg - 3 for azure) (required for air gap protect pool)

            display_vendor_id (int)     -- storage Class id for that vendor (eg - 401 for azure hot) (required for air gap protect pool)

            region_id        (int)      --  Cloud Hypervisor specific region ID

            tape_storage (boolean)      -- if library passed is tape library. 

    Returns:
        StoragePool object if creation is successful

    Raises:
        Exception if creation is unsuccessful
    """
    username = kwargs.get('username', None)
    password = kwargs.get('password', None)
    credential_name = kwargs.get('credential_name', None)
    cloud_server_type = kwargs.get('cloud_server_type', None)
    library_name = kwargs.get('library_name', None)
    tape_storage = False

    region = kwargs.get('region', None)
    vendor_id = kwargs.get('vendor_id', None)
    display_vendor_id = kwargs.get('display_vendor_id', None)
    region_id = kwargs.get('region_id', None)

    if library_name:
        library_object = self._commcell_object.disk_libraries.get(library_name)
        library_type = library_object.library_properties.get('libraryType', None)
        tape_storage = True if library_type == 1 else tape_storage


    if ((ddb_ma is not None and not (isinstance(dedup_path, str) or isinstance(dedup_path, list))) or
            not (isinstance(storage_pool_name, str) or not isinstance(mountpath, str))):
        raise SDKException('Storage', '101')

    if isinstance(media_agent, MediaAgent):
        media_agent = media_agent
    elif isinstance(media_agent, str):
        media_agent = MediaAgent(self._commcell_object, media_agent)
    else:
        raise SDKException('Storage', '103')

    if (isinstance(ddb_ma, str) or isinstance(ddb_ma, MediaAgent)) and isinstance(dedup_path, str):
        ddb_ma = [ddb_ma]
        dedup_path = [dedup_path]

    if isinstance(ddb_ma, list) and isinstance(dedup_path, list):
        if len(ddb_ma) != len(dedup_path):
            raise SDKException('Storage', '101')

    if library_name is not None and mountpath != '':
        raise SDKException('Storage', '101')

    if ddb_ma is not None and (len(ddb_ma) > 6 or len(dedup_path) > 6):
        raise SDKException('Storage', '110')

    if ddb_ma is not None:
        for i in range(len(ddb_ma)):
            if isinstance(ddb_ma[i], MediaAgent):
                ddb_ma[i] = ddb_ma[i]
            elif isinstance(ddb_ma[i], str):
                ddb_ma[i] = MediaAgent(self._commcell_object, ddb_ma[i])
            else:
                raise SDKException('Storage', '103')

    request_json = {
        "storagePolicyName": storage_pool_name,
        "type": "CVA_REGULAR_SP",
        "copyName": "Primary",
        "numberOfCopies": 1,
        "storage": [
            {
                "path": mountpath,
                "mediaAgent": {
                    "mediaAgentId": int(media_agent.media_agent_id),
                    "mediaAgentName": media_agent.media_agent_name
                }
            }
        ],
        "storagePolicyCopyInfo": {
            "copyType": "SYNCHRONOUS",
            "isFromGui": True,
            "active": "SET_TRUE",
            "isDefault": "SET_TRUE",
            "numberOfStreamsToCombine": 1,
            "retentionRules": {
                "retentionFlags": {
                    "enableDataAging": "SET_TRUE"
                },
                "retainBackupDataForDays": -1,
                "retainBackupDataForCycles": -1,
                "retainArchiverDataForDays": -1
            },
            "library": {
                "libraryId": 0,
            },
            "mediaAgent": {
                "mediaAgentId": int(media_agent.media_agent_id),
                "mediaAgentName": media_agent.media_agent_name
            }
        }
    }

    if cloud_server_type and int(cloud_server_type) > 0:
        request_json["storage"][0]["deviceType"] = cloud_server_type

    if region_id is not None:
        request_json["storage"][0]["metallicStorageInfo"] = {
            "region": [
                {
                    "regionId": region_id
                }
            ],
            "storageClass": [
                "CONTAINER_DEFAULT"
            ],
            "replication": [
                "NONE"
            ]
        }
        request_json["region"] = {"regionId": region_id}

    if username is not None:
        request_json["storage"][0]["credentials"] = {"userName": username}

    if password is not None:
        request_json["storage"][0]["credentials"]["password"] = b64encode(password.encode()).decode()

    if credential_name is not None:
        request_json["storage"][0]["savedCredential"] = {"credentialName": credential_name}

    if library_name is not None:
        request_json["storage"] = []
        request_json["storagePolicyCopyInfo"]["library"]["libraryName"] = library_name

    if ddb_ma is not None or dedup_path is not None:
        maInfoList = []
        for ma, path in zip(ddb_ma, dedup_path):
            maInfoList.append({
                "mediaAgent": {
                    "mediaAgentId": int(ma.media_agent_id),
                    "mediaAgentName": ma.media_agent_name
                },
                "subStoreList": [
                    {
                        "accessPath": {
                            "path": path
                        },
                        "diskFreeThresholdMB": 5120,
                        "diskFreeWarningThreshholdMB": 10240
                    }]
            })

        request_json["storagePolicyCopyInfo"].update({
            "storagePolicyFlags": {
                "blockLevelDedup": "SET_TRUE",
                "enableGlobalDeduplication": "SET_TRUE"
            },
            "dedupeFlags": {
                "enableDeduplication": "SET_TRUE",
                "enableDASHFull": "SET_TRUE",
                "hostGlobalDedupStore": "SET_TRUE"
            },
            "DDBPartitionInfo": {
                "maInfoList": maInfoList
            }
        })
    elif tape_storage:
        request_json["storagePolicyCopyInfo"].update({
            "storagePolicyFlags": {
                "globalAuxCopyPolicy": "SET_TRUE"
            },
            "copyFlags": {
                "preserveEncryptionModeAsInSource": "SET_TRUE"
            },
            "extendedFlags": {
                "globalAuxCopyPolicy": "SET_TRUE"
            }
        })
    else:
        request_json["storagePolicyCopyInfo"].update({
            "storagePolicyFlags": {
                "globalStoragePolicy": "SET_TRUE"
            },
            "copyFlags": {
                "preserveEncryptionModeAsInSource": "SET_TRUE"
            },
            "extendedFlags": {
                "globalStoragePolicy": "SET_TRUE"
            }
        })

    # air gap protect storage
    if cloud_server_type == 400:
        del request_json["storage"][0]["path"]
        request_json["storage"][0]["savedCredential"] = {"credentialId": 0}

        metallic_Storage = {
            "region": [
                {
                    "regionName": region
                }
            ],
            "displayVendorId": display_vendor_id,
            "vendorId": vendor_id
        }
        request_json["storage"][0]["metallicStorageInfo"] = metallic_Storage

    flag, response = self._commcell_object._cvpysdk_object.make_request(
        'POST', self._add_storage_pool_api, request_json
    )

    if flag:
        if response.json():
            error_code = response.json()['error']['errorCode']

            if int(error_code) != 0:
                error_message = response.json()['error']['errorMessage']
                o_str = 'Failed to create storage pool\nError: "{0}"'

                raise SDKException('StoragePool', '102', o_str.format(error_message))
        else:
            raise SDKException('Response', '102')
    else:
        response_string = self._commcell_object._update_response_(response.text)
        raise SDKException('Response', '101', response_string)

    self.refresh()
    self._commcell_object.disk_libraries.refresh()
    return self.get(storage_pool_name)
def add_air_gap_protect(self, storage_pool_name, media_agent, storage_type, storage_class, region_name, ddb_ma=None, dedup_path=None)

Adds a new air gap protect storage pool to commcell

Args:
    storage_pool_name   (str)       --  name of new storage pool to add

    media_agent         (str/object)--  name or instance of media agent

    storage_type        (str)        -- name of the cloud vendor (str, eg - "Microsoft Azure storage") (same as UI)

    storage_class       (str)        -- storage class (str, eg - "Hot","Cool") (same as UI)

    region_name (str)      --  name of the geographical region for storage (same as UI)

    ddb_ma              (list<str/object>/str/object)   --  list of (name of name or instance)
                                                            or name or instance of dedupe media agent

    dedup_path          (list<str>/str)       --  list of paths or path where the DDB should be stored

Returns:
    StoragePool object if creation is successful

Raises:
    SDKException, if invalid parameters provided
Expand source code Browse git
def add_air_gap_protect(self, storage_pool_name, media_agent, storage_type, storage_class, region_name,
                        ddb_ma=None, dedup_path=None):
    """
        Adds a new air gap protect storage pool to commcell

            Args:
                storage_pool_name   (str)       --  name of new storage pool to add

                media_agent         (str/object)--  name or instance of media agent

                storage_type        (str)        -- name of the cloud vendor (str, eg - "Microsoft Azure storage") (same as UI)

                storage_class       (str)        -- storage class (str, eg - "Hot","Cool") (same as UI)

                region_name (str)      --  name of the geographical region for storage (same as UI)

                ddb_ma              (list<str/object>/str/object)   --  list of (name of name or instance)
                                                                        or name or instance of dedupe media agent

                dedup_path          (list<str>/str)       --  list of paths or path where the DDB should be stored

            Returns:
                StoragePool object if creation is successful

            Raises:
                SDKException, if invalid parameters provided

    """
    license_type_dict = StoragePoolConstants.AIR_GAP_PROTECT_STORAGE_TYPES
    error_message = ""
    if storage_type.upper() in license_type_dict:
        available_storage_classes = license_type_dict[storage_type.upper()]
        if storage_class.upper() in available_storage_classes:
            vendor_id = available_storage_classes[storage_class.upper()]["vendorId"]
            display_vendor_id = available_storage_classes[storage_class.upper()]["displayVendorId"]
        else:
            error_message += f"Invalid storage class provided. Valid storage class {list(available_storage_classes.keys())}"
    else:
        error_message += f"  Invalid storage type provided. {list(license_type_dict.keys())}"

    if error_message:
        raise SDKException('Storage', '101', error_message)

    region = None
    available_regions = []

    #  API call to fetch the region name - sourced directly from the vendor
    flag, response = self._commcell_object._cvpysdk_object.make_request('GET', self._metallic_storage_api)
    if flag:
        if response.json():
            if "storageInformation" in response.json():
                for storage_info in response.json()["storageInformation"]:
                    if (int(storage_info["vendorId"]) == int(vendor_id)) and (int(storage_info["displayVendorId"]) == int(display_vendor_id)):
                        for region_dict in storage_info["region"]:
                            available_regions.append(region_dict["displayName"])
                            if region_dict["displayName"] == region_name:
                                region = region_dict["regionName"]
                                break

                    if region:
                        break

                if region is None:
                    if not available_regions:
                        raise SDKException('Storage', '101',
                                           f"Active license is required to configure {storage_type} - {storage_class} Air Gap Protect storage")
                    else:
                        raise SDKException('Storage', '101',
                                           f"Invalid region: {region_name} ,\nValid regions: {available_regions}")
            else:
                raise SDKException('Storage', '101', "Unexpected response returned while fetching Air Gap Protect storage details")
        else:
            raise SDKException('Response', '102')
    else:
        response_string = self._commcell_object._update_response_(response.text)
        raise SDKException('Response', '101', response_string)

    # cloud server type for air gap protect is 400
    cloud_server_type = 400

    return self.add(storage_pool_name=storage_pool_name, mountpath=None, media_agent=media_agent, ddb_ma=ddb_ma,
                    dedup_path=dedup_path, cloud_server_type=cloud_server_type, region=region, vendor_id=vendor_id,
                    display_vendor_id=display_vendor_id)
def delete(self, storage_pool_name)

deletes the specified storage pool.

Args

storage_pool_name (str) – name of the storage pool to delete

Raises

SDKException: if type of the storage pool name is not string

if failed to delete storage pool

if no storage pool exists with the given name

if response is empty

if response is not success
Expand source code Browse git
def delete(self, storage_pool_name):
    """deletes the specified storage pool.

        Args:
            storage_pool_name (str)  --  name of the storage pool to delete

        Raises:
            SDKException:
                if type of the storage pool name is not string

                if failed to delete storage pool

                if no storage pool exists with the given name

                if response is empty

                if response is not success

    """

    if not isinstance(storage_pool_name, str):
        raise SDKException('Storage', '101')
    else:
        storage_pool_name = storage_pool_name.lower()

        if self.has_storage_pool(storage_pool_name):
            storage_pool_id = self._storage_pools[storage_pool_name]

            delete_storage_pool = self._services['DELETE_STORAGE_POOL'] % (storage_pool_id)

            flag, response = self._cvpysdk_object.make_request('DELETE', delete_storage_pool)

            if flag:
                error_code = response.json()['error']['errorCode']
                if int(error_code) != 0:
                    error_message = response.json()['error']['errorMessage']
                    o_str = f'Failed to delete storage pools {storage_pool_name}'
                    o_str += '\nError: "{0}"'.format(error_message)
                    raise SDKException('Storage', '102', o_str)
                else:
                    # initialize the storage pool again
                    # so the storage pool object has all the storage pools
                    self.refresh()
                    # as part of storage pool we might delete library so initialize the libraries again
                    self._commcell_object.disk_libraries.refresh()
            else:
                response_string = self._update_response_(response.text)
                raise SDKException('Response', '101', response_string)
        else:
            raise SDKException(
                'Storage',
                '102',
                'No storage pool exists with name: {0}'.format(storage_pool_name)
            )
def get(self, name)

Returns the id of the storage pool for the given storage pool name.

Args

name (str) – name of the storage pool to get the id of

Returns

str - id of the storage pool for the given storage pool name

Raises

SDKException: if no storage pool exists with the given name

Expand source code Browse git
def get(self, name):
    """Returns the id of the storage pool for the given storage pool name.

        Args:
            name    (str)   --  name of the storage pool to get the id of

        Returns:
            str     -   id of the storage pool for the given storage pool name

        Raises:
            SDKException:
                if no storage pool exists with the given name

    """
    self.refresh()
    name = name.lower()

    if self.has_storage_pool(name):
        return StoragePool(self._commcell_object, name, storage_pool_id=self._storage_pools[name])
    else:
        raise SDKException('StoragePool', '103')
def get_air_gap_protect(self, company_id=None)

Returns the list of air gap protect storage pools in the commcell.

Args

company_id (int) – id of the company to get the air gap protect storage pools for (optional, default is None which returns all air gap protect storage pools)

Returns

dict - dictionary of air gap protect storage pools with name as key and id as value

    {
        "storage_pool1_name": storage_pool1_id,
        "storage_pool2_name": storage_pool2_id
    }

Raises

SDKException: if response is empty

if response is not success
Expand source code Browse git
def get_air_gap_protect(self, company_id = None):
    """
    Returns the list of air gap protect storage pools in the commcell.
    
    Args:
        company_id (int) -- id of the company to get the air gap protect storage pools for
                            (optional, default is None which returns all air gap protect storage pools)
    
    Returns:
        dict - dictionary of air gap protect storage pools with name as key and id as value
            
                {
                    "storage_pool1_name": storage_pool1_id,
                    "storage_pool2_name": storage_pool2_id
                }  
    
    Raises:
        SDKException:
            if response is empty

            if response is not success
    """
    headers = self._commcell_object._headers.copy()
    headers['Accept'] = 'application/json'
    if company_id:
        headers['onlygetcompanyownedentities'] = '1'
        headers['operatorcompanyid'] = f'{company_id}'

    flag, response = self._cvpysdk_object.make_request(
        'GET', self.__get_agp_storage_api, headers=headers
    )

    if flag:
        storage_pools = {}
        response = response.json()
        if response is None or response.get('cloudStorage') is None:
            storage_pool_list = []
        else:
            storage_pool_list = response['cloudStorage']
        if not isinstance(storage_pool_list, list):
            storage_pool_list = [storage_pool_list]
        if response:
            for pool in storage_pool_list:
                name = pool['name']
                storage_pool_id = pool['id']

                storage_pools[name] = storage_pool_id

        return storage_pools
    else:
        response_string = self._update_response_(response.text)
        raise SDKException('Response', '101', response_string)
def get_storage_pools_for_a_company(self, company_id, storage_type: StorageType = None)

Gets all the storage pools associated with the Commcell environment.

Args

company_id - id of the company for which the associated storge pools are to be fetched

Returns

dict - consists of all storage pools added to the commcell

{
    "storage_pool1_name": storage_pool1_id,

    "storage_pool2_name": storage_pool2_id
}

Raises

SDKException: if response is empty

if response is not success
Expand source code Browse git
def get_storage_pools_for_a_company(self, company_id, storage_type: StorageType = None):
    """Gets all the storage pools associated with the Commcell environment.

        Args:
            company_id - id of the company for which the associated storge pools are to be fetched

        Returns:
            dict    -   consists of all storage pools added to the commcell

                {
                    "storage_pool1_name": storage_pool1_id,

                    "storage_pool2_name": storage_pool2_id
                }

        Raises:
            SDKException:
                if response is empty

                if response is not success

    """
    headers = self._commcell_object._headers.copy()
    headers['Accept'] = 'application/json'
    headers['onlygetcompanyownedentities'] = '1'
    headers['operatorcompanyid'] = f'{company_id}'

    flag, response = self._cvpysdk_object.make_request(
        'GET', self._storage_pools_api, headers=headers
    )

    if flag:
        storage_pools = {}
        response = response.json()
        if response is None or response.get('storagePoolList') is None:
            storage_pool_list = []
        else:
            storage_pool_list = response['storagePoolList']
        if not isinstance(storage_pool_list, list):
            storage_pool_list = [storage_pool_list]
        if response:
            for pool in storage_pool_list:
                if storage_type and pool['storageType'] != storage_type:
                    continue
                # skip agp pools for cloud storage type
                if storage_type == StorageType.CLOUD and 401 <= pool['libraryVendorType'] <= 499:
                    continue
                name = pool['storagePoolEntity']['storagePoolName']
                storage_pool_id = pool['storagePoolEntity']['storagePoolId']

                storage_pools[name] = storage_pool_id

        return storage_pools
    else:
        response_string = self._update_response_(response.text)
        raise SDKException('Response', '101', response_string)
def has_storage_pool(self, name)

Checks if a storage pool exists in the Commcell with the input storage pool name.

Args

name (str) – name of the storage pool

Returns

bool - boolean output whether the storage pool exists in the commcell or not

Expand source code Browse git
def has_storage_pool(self, name):
    """Checks if a storage pool exists in the Commcell with the input storage pool name.

        Args:
            name    (str)   --  name of the storage pool

        Returns:
            bool    -   boolean output whether the storage pool exists in the commcell or not

    """
    return self._storage_pools and name.lower() in self._storage_pools
def hyperscale_create_storage_pool(self, storage_pool_name, media_agents)

Create new storage pool for hyperscale

Args

storage_pool_name (string) – Name of the storage pools to create

media_agents (List) – List of 3 media agents with name's(str) or instance of media agent's(object)

Example
["ma1","ma2","ma3"]

Return

flag, response – response returned by the REST API call

Expand source code Browse git
def hyperscale_create_storage_pool(self, storage_pool_name, media_agents):
    """
        Create new storage pool for hyperscale
        Args:
            storage_pool_name (string) -- Name of the storage pools to create

            media_agents      (List)   -- List of 3 media agents with name's(str)
                                            or instance of media agent's(object)

            Example: ["ma1","ma2","ma3"]

        Return:
             flag, response -- response returned by the REST API call
    """

    if not isinstance(media_agents, list):
        raise SDKException('Storage', '101')
    if not isinstance(storage_pool_name, str):
        raise SDKException('Storage', '101')

    mediagent_obj = []
    for media_agent in media_agents:
        if isinstance(media_agent, MediaAgent):
            mediagent_obj.append(media_agent)
        elif isinstance(media_agent, str):
            mediagent_obj.append(self._commcell_object.media_agents.get(media_agent))
        else:
            raise SDKException('Storage', '103')
    if len(mediagent_obj) <= 2:
        raise SDKException('Storage', '102', "minimum 3 media agents are required")

    request_xml = """<App_CreateStoragePolicyReq storagePolicyName="{0}" copyName="{0}_Primary" type="1"
                                 numberOfCopies="1">
                                <storagePolicyCopyInfo>
                                    <storagePolicyFlags scaleOutStoragePolicy="1"/>
                                </storagePolicyCopyInfo>
                                <storage>
                                    <mediaAgent mediaAgentId="{4}" mediaAgentName="{1}" displayName="{1}"/>
                                </storage>
                                <storage>
                                    <mediaAgent mediaAgentId="{5}" mediaAgentName="{2}" displayName="{2}"/>
                                </storage>
                                <storage>
                                    <mediaAgent mediaAgentId="{6}" mediaAgentName="{3}" displayName="{3}"/>
                                </storage>
                                <scaleoutConfiguration configurationType="1"/>
                            </App_CreateStoragePolicyReq>
                            """.format(storage_pool_name, mediagent_obj[0].media_agent_name,
                                       mediagent_obj[1].media_agent_name, mediagent_obj[2].media_agent_name,
                                       mediagent_obj[0].media_agent_id, mediagent_obj[1].media_agent_id,
                                       mediagent_obj[2].media_agent_id)

    flag, response = self._commcell_object._cvpysdk_object.make_request(
        'POST', self._add_storage_pool_api, request_xml
    )
    if flag:
        if response.json():
            error_code = response.json()['error']['errorCode']

            if int(error_code) != 0:
                error_message = response.json()['error']['errorMessage']
                o_str = 'Failed to create storage pool\nError: "{0}"'

                raise SDKException('StoragePool', '102', o_str.format(error_message))
        else:
            raise SDKException('Response', '102')
    else:
        response_string = self._commcell_object._update_response_(response.text)
        raise SDKException('Response', '101', response_string)

    self.refresh()
    return self.get(storage_pool_name)
def refresh(self)

Refresh the list of storage pools associated to the Commcell.

Expand source code Browse git
def refresh(self):
    """Refresh the list of storage pools associated to the Commcell."""
    self._storage_pools = self._get_storage_pools()
class StorageType (value, names=None, *, module=None, qualname=None, type=None, start=1)

Class IntEnum to represent different storage types

Expand source code Browse git
class StorageType(IntEnum):
    """Class IntEnum to represent different storage types"""
    DISK = 1,
    CLOUD = 2,
    HYPERSCALE = 3,
    TAPE = 4

Ancestors

  • enum.IntEnum
  • builtins.int
  • enum.Enum

Class variables

var CLOUD
var DISK
var HYPERSCALE
var TAPE
class WORMLockType (value, names=None, *, module=None, qualname=None, type=None, start=1)

Class IntFlag to represent different WORM lock types flag values

Expand source code Browse git
class WORMLockType(IntFlag):
    """Class IntFlag to represent different WORM lock types flag values"""
    COPY = 1,  # copy level software WORM (compliance lock)
    STORAGE = 2,  # storage level hardware WORM
    OBJECT = 4,  # object level storage WORM
    BUCKET = 8  # bucket level storage WORM

Ancestors

  • enum.IntFlag
  • builtins.int
  • enum.Flag
  • enum.Enum

Class variables

var BUCKET
var COPY
var OBJECT
var STORAGE