diff --git a/storops/unity/enums.py b/storops/unity/enums.py index d2ade5d8..4c284073 100644 --- a/storops/unity/enums.py +++ b/storops/unity/enums.py @@ -392,6 +392,7 @@ class HostLUNAccessEnum(UnityEnum): PRODUCTION = (1, 'Production LUNs only') SNAPSHOT = (2, 'LUN Snapshots only') BOTH = (3, 'Production LUNs and Snapshots') + # Applies to consistency groups only MIXED = (0xffff, 'Mixed') diff --git a/storops/unity/resource/cg.py b/storops/unity/resource/cg.py new file mode 100644 index 00000000..9c55513a --- /dev/null +++ b/storops/unity/resource/cg.py @@ -0,0 +1,239 @@ +# Copyright (c) 2018 Dell Inc. or its subsidiaries. +# All Rights Reserved. +# +# 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. + + +from __future__ import unicode_literals +from storops import HostLUNAccessEnum +from storops.exception import UnityStorageResourceNameInUseError, \ + UnityConsistencyGroupNameInUseError +from storops.unity import enums +from storops.unity.resource.storage_resource import UnityStorageResource, \ + UnityStorageResourceList + +from storops.unity.resource import lun as lun_mod +from storops.unity.resource.lun import UnityLun +from storops.unity.resource.snap import UnitySnap, UnitySnapList + +__author__ = 'Peter Wang' + +import logging + +log = logging.getLogger(__name__) + + +class UnityConsistencyGroup(UnityStorageResource): + """ + Create a consistency group (former LUN group). + """ + + @classmethod + def create(cls, cli, name, description=None, is_repl_dst=None, + snap_schedule=None, tiering_policy=None, + is_data_deduction_enabled=None, + hosts=None, lun_add=None): + req_body = cls._compose_cg_parameters(cli, name, description, + is_repl_dst, + snap_schedule, tiering_policy, + is_data_deduction_enabled, + hosts, + lun_add) + resp = cli.type_action(UnityStorageResource().resource_class, + 'createConsistencyGroup', **req_body) + try: + resp.raise_if_err() + except UnityStorageResourceNameInUseError: + raise UnityConsistencyGroupNameInUseError() + except: # noqa + raise + return UnityConsistencyGroup(_id=resp.resource_id, cli=cli) + + @property + def name(self): + if hasattr(self, '_name') and self._name is not None: + name = self._name + else: + if not self._is_updated(): + self.update() + name = self._get_value_by_key('name') + return name + + @name.setter + def name(self, new_name): + self.modify(name=new_name) + + def modify(self, name=None, description=None, is_repl_dst=None, + snap_schedule=None, tiering_policy=None, + is_data_deduction_enabled=None, hosts=None, + lun_add=None, lun_remove=None, host_add=None, + host_remove=None, lun_modify=None): + req_body = self._compose_cg_parameters( + self._cli, name, description, + is_repl_dst, snap_schedule, tiering_policy, + is_data_deduction_enabled, hosts, + lun_add, lun_remove, host_add, host_remove, lun_modify) + resp = self._cli.action(UnityStorageResource().resource_class, + self.get_id(), 'modifyConsistencyGroup', + **req_body) + resp.raise_if_err() + return resp + + @staticmethod + def _compose_cg_parameters(cli, name=None, description=None, + is_repl_dst=None, + snap_schedule=None, tiering_policy=None, + is_data_deduction_enabled=None, + hosts=None, + lun_add=None, + lun_remove=None, + host_add=None, + host_remove=None, + lun_modify=None): + host_access = UnityConsistencyGroup._wrap_host_list(hosts, cli) + host_access_add = UnityConsistencyGroup._wrap_host_list(host_add, cli) + + lun_add = UnityConsistencyGroup._wrap_lun_list(lun_add) + lun_remove = UnityConsistencyGroup._wrap_lun_list(lun_remove) + + req_body = cli.make_body( + name=name, + description=description, + replicationParameters=cli.make_body( + isReplicationDestination=is_repl_dst), + fastVPParameters=cli.make_body( + tieringPolicy=tiering_policy), + dataReductionParameters=cli.make_body( + isDataReductionEnabled=is_data_deduction_enabled + ), + snapScheduleParameters=cli.make_body( + snapSchedule=snap_schedule + ), + blockHostAccess=cli.make_body(host_access), + lunAdd=cli.make_body(lun_add), + lunRemove=cli.make_body(lun_remove), + addBlockHostAccess=cli.make_body(host_access_add), + removeBlockHostAccess=cli.make_body(host_remove), + ) + # Empty host access can be used to wipe the host_access + if lun_modify is not None: + lun_modify = cli.make_body(lun_modify, allow_empty=True) + req_body['lunModify'] = lun_modify + + return req_body + + def modify_lun(self, lun, name=None, size=None, host_access=None, + description=None, sp=None, io_limit_policy=None, + tiering_policy=None, is_compression=None): + + lun_modify = self._cli.make_body(lun=lun, + name=name, + description=description) + # `hostAccess` could be empty list which is used to remove all host + # access + lun_parameters = lun_mod.prepare_lun_parameters( + size=size, + host_access=host_access, + sp=sp, + io_limit_policy=io_limit_policy, + tiering_policy=tiering_policy, + is_compression=is_compression) + if lun_parameters: + lun_modify['lunParameters'] = lun_parameters + + return self.modify(lun_modify=[lun_modify]) + + @staticmethod + def _wrap_host_list(host_list, cli): + def make_host_elem(host): + return cli.make_body(host=host, + accessMask=enums.HostLUNAccessEnum.BOTH) + + if host_list is not None: + ret = list(map(make_host_elem, host_list)) + else: + ret = None + return ret + + @staticmethod + def _wrap_lun_list(lun_list): + if lun_list is not None: + ret = list(map(lambda lun: {'lun': lun}, lun_list)) + else: + ret = None + return ret + + def add_lun(self, *lun_list): + return self.modify(lun_add=lun_list) + + def remove_lun(self, *lun_list): + return self.modify(lun_remove=lun_list) + + def replace_lun(self, *lun_list): + """Replaces the exiting LUNs to lun_list.""" + existing_ids = {lun.get_id() for lun in self.luns} + new_ids = {lun.get_id() for lun in lun_list} + add_ids = new_ids - existing_ids + log.debug("Adding LUN(s) '{}' to cg {}".format(add_ids, self.get_id())) + lun_add = [UnityLun(_id=_id, cli=self._cli) for _id in add_ids] + remove_ids = existing_ids - new_ids + log.debug("Removing LUN(s) '{}' from cg '{}'".format(remove_ids, + self.get_id())) + lun_remove = [UnityLun(_id=_id, cli=self._cli) for _id in remove_ids] + return self.modify(lun_add=lun_add, lun_remove=lun_remove) + + def attach_to(self, host=None, access_mask=HostLUNAccessEnum.BOTH): + """Attaches all member LUNs to the specified host.""" + raise NotImplementedError() + + def detach_from(self, host=None): + """Detaches all members from host, if None, detach from all hosts.""" + raise NotImplementedError() + + def set_host_access(self, *hosts): + return self.modify(hosts=hosts) + + def add_host_access(self, *hosts): + return self.modify(host_add=hosts) + + def remove_host_access(self, *hosts): + return self.modify(host_remove=hosts) + + def create_snap(self, name=None, description=None, is_auto_delete=None, + retention_duration=None): + clz = UnitySnap + return clz.create(self._cli, self, name=name, description=description, + is_auto_delete=is_auto_delete, + retention_duration=retention_duration, + is_read_only=None, fs_access_type=None) + + @property + def snapshots(self): + clz = UnitySnapList + snaps = clz(cli=self._cli, storage_resource=self) + return list(filter(lambda snap: snap.snap_group is None, snaps)) + + +class UnityConsistencyGroupList(UnityStorageResourceList): + type_cg = enums.StorageResourceTypeEnum.CONSISTENCY_GROUP + + def __init__(self, **the_filter): + the_filter['type'] = self.type_cg + super(UnityConsistencyGroupList, self).__init__(**the_filter) + + @classmethod + def get_resource_class(cls): + return UnityConsistencyGroup + + def _filter(self, item): + return item.type == self.type_cg diff --git a/storops/unity/resource/host.py b/storops/unity/resource/host.py index 1caf804d..98c31122 100644 --- a/storops/unity/resource/host.py +++ b/storops/unity/resource/host.py @@ -349,9 +349,6 @@ def delete_initiator(self, uid): initiators += self.iscsi_host_initiators for item in initiators: if item.initiator_id == uid: - # remove from the host initiator list first, - # otherwise delete initiator will not work - item.modify(None) resp = item.delete() resp.raise_if_err() break diff --git a/storops/unity/resource/lun.py b/storops/unity/resource/lun.py index 2de69b0f..295ea145 100644 --- a/storops/unity/resource/lun.py +++ b/storops/unity/resource/lun.py @@ -22,8 +22,9 @@ UnityResourceNotFoundError from storops.lib.thinclone_helper import TCHelper from storops.lib.version import version +from storops.unity.client import UnityClient from storops.unity.enums import TieringPolicyEnum, NodeEnum, \ - HostLUNAccessEnum, ThinCloneActionEnum + HostLUNAccessEnum, ThinCloneActionEnum, StorageResourceTypeEnum from storops.unity.resource import UnityResource, UnityResourceList from storops.unity.resource.host import UnityHostList from storops.unity.resource.snap import UnitySnap, UnitySnapList @@ -36,13 +37,49 @@ log = logging.getLogger(__name__) +def prepare_lun_parameters(**kwargs): + sp = kwargs.get('sp') + if isinstance(sp, UnityStorageProcessor): + sp_node = sp.to_node_enum() + elif isinstance(sp, NodeEnum): + sp_node = sp + else: + sp_node = NodeEnum.parse(sp) + NodeEnum.verify(sp_node) + + TieringPolicyEnum.verify(kwargs.get('tiering_policy')) + + lun_parameters = UnityClient.make_body( + isThinEnabled=kwargs.get('is_thin'), + isCompressionEnabled=kwargs.get('is_compression'), + size=kwargs.get('size'), + pool=kwargs.get('pool'), + defaultNode=sp_node, + fastVPParameters=UnityClient.make_body( + tieringPolicy=kwargs.get('tiering_policy')), + ioLimitParameters=UnityClient.make_body( + ioLimitPolicy=kwargs.get('io_limit_policy'))) + + # Empty host access can be used to wipe the host_access + host_access = UnityClient.make_body(kwargs.get('host_access'), + allow_empty=True) + + if host_access is not None: + lun_parameters['hostAccess'] = host_access + return lun_parameters + + class UnityLun(UnityResource): + _is_cg_member = None + _cg = None + @classmethod def get_nested_properties(cls): return ( 'pool.raid_type', 'pool.isFASTCacheEnabled', 'host_access.host.name', + 'storage_resource.type' # To avoid query parent type ) @classmethod @@ -79,6 +116,27 @@ def name(self): def name(self, new_name): self.modify(name=new_name) + @property + def is_cg_member(self): + """Allows setting storage resource as a member LUN.""" + if self._is_cg_member is None: # None means unknown, requires a query + return (self.storage_resource.type == + StorageResourceTypeEnum.CONSISTENCY_GROUP) + else: + return self._is_cg_member + + @is_cg_member.setter + def is_cg_member(self, is_cg_member): + self._is_cg_member = is_cg_member + + @property + def cg(self): + if self.is_cg_member and self._cg is None: + from storops.unity.resource.cg import UnityConsistencyGroup + self._cg = UnityConsistencyGroup(cli=self._cli, + _id=self.storage_resource.id) + return self._cg + @property def io_limit_rule(self): rule = None @@ -124,63 +182,47 @@ def expand(self, new_size): @staticmethod def _compose_lun_parameter(cli, **kwargs): - sp = kwargs.get('sp') - if isinstance(sp, UnityStorageProcessor): - sp_node = sp.to_node_enum() - elif isinstance(sp, NodeEnum): - sp_node = sp - else: - sp_node = NodeEnum.parse(sp) - - TieringPolicyEnum.verify(kwargs.get('tiering_policy')) - NodeEnum.verify(sp_node) # TODO: snap_schedule - req_body = cli.make_body( + body = cli.make_body( name=kwargs.get('name'), description=kwargs.get('description'), replicationParameters=cli.make_body( - isReplicationDestination=kwargs.get('is_repl_dst') - ), - lunParameters=cli.make_body( - isThinEnabled=kwargs.get('is_thin'), - isCompressionEnabled=kwargs.get('is_compression'), - size=kwargs.get('size'), - pool=kwargs.get('pool'), - defaultNode=sp_node, - fastVPParameters=cli.make_body( - tieringPolicy=kwargs.get('tiering_policy')), - ioLimitParameters=cli.make_body( - ioLimitPolicy=kwargs.get('io_limit_policy')) - ) - ) - - # Empty host access can be used to wipe the host_access - host_access_value = cli.make_body( - kwargs.get('host_access'), allow_empty=True) + isReplicationDestination=kwargs.get('is_repl_dst'))) - if host_access_value is not None: - if 'lunParameters' not in req_body: - req_body['lunParameters'] = {} - req_body['lunParameters']['hostAccess'] = host_access_value - - return req_body + # `hostAccess` could be empty list which is used to remove all host + # access + lun_parameters = prepare_lun_parameters(**kwargs) + if lun_parameters: + body['lunParameters'] = lun_parameters + return body def modify(self, name=None, size=None, host_access=None, description=None, sp=None, io_limit_policy=None, is_repl_dst=None, tiering_policy=None, snap_schedule=None, is_compression=None): + if self.is_cg_member: + if is_repl_dst is not None or snap_schedule is not None: + log.warning('LUN in CG not support to modify `is_repl_dst` and' + ' `snap_schedule`.') + return self.cg.modify_lun(self, name=name, size=size, + host_access=host_access, + description=description, sp=sp, + io_limit_policy=io_limit_policy, + tiering_policy=tiering_policy, + is_compression=is_compression) - req_body = self._compose_lun_parameter( - self._cli, name=name, pool=None, size=size, sp=sp, - host_access=host_access, description=description, - io_limit_policy=io_limit_policy, is_repl_dst=is_repl_dst, - tiering_policy=tiering_policy, snap_schedule=snap_schedule, - is_compression=is_compression) - resp = self._cli.action(UnityStorageResource().resource_class, - self.get_id(), 'modifyLun', **req_body) - resp.raise_if_err() - return resp + else: + req_body = self._compose_lun_parameter( + self._cli, name=name, pool=None, size=size, sp=sp, + host_access=host_access, description=description, + io_limit_policy=io_limit_policy, is_repl_dst=is_repl_dst, + tiering_policy=tiering_policy, snap_schedule=snap_schedule, + is_compression=is_compression) + resp = self._cli.action(UnityStorageResource().resource_class, + self.get_id(), 'modifyLun', **req_body) + resp.raise_if_err() + return resp def delete(self, async=False, force_snap_delete=False, force_vvol_delete=False): diff --git a/storops/unity/resource/storage_resource.py b/storops/unity/resource/storage_resource.py index 387ad007..3f9f1a1d 100644 --- a/storops/unity/resource/storage_resource.py +++ b/storops/unity/resource/storage_resource.py @@ -15,11 +15,7 @@ # under the License. from __future__ import unicode_literals -from storops.exception import UnityStorageResourceNameInUseError, \ - UnityConsistencyGroupNameInUseError -from storops.unity import enums from storops.unity.resource import UnityResource, UnityResourceList -import storops.unity.resource.snap __author__ = 'Cedric Zhuang' @@ -27,7 +23,7 @@ class UnityStorageResource(UnityResource): @classmethod def get(cls, cli, _id=None): - if not isinstance(_id, (cls, UnityConsistencyGroup)): + if not isinstance(_id, cls): ret = cls(_id=_id, cli=cli) else: ret = _id @@ -47,123 +43,3 @@ class UnityStorageResourceList(UnityResourceList): @classmethod def get_resource_class(cls): return UnityStorageResource - - -class UnityConsistencyGroup(UnityResource): - @classmethod - def create(cls, cli, name, description=None, lun_list=None, - hosts=None): - lun_list = cls._wrap_lun_list(lun_list) - hosts = cls._wrap_host_list(hosts, cli) - - req_body = cli.make_body(name=name, - description=description, - lunAdd=lun_list, - blockHostAccess=hosts) - resp = cli.type_action(UnityStorageResource().resource_class, - 'createConsistencyGroup', **req_body) - - try: - resp.raise_if_err() - except UnityStorageResourceNameInUseError: - raise UnityConsistencyGroupNameInUseError() - except: # noqa - raise - - return UnityConsistencyGroup(_id=resp.resource_id, cli=cli) - - @property - def name(self): - if hasattr(self, '_name') and self._name is not None: - name = self._name - else: - if not self._is_updated(): - self.update() - name = self._get_value_by_key('name') - return name - - @name.setter - def name(self, new_name): - self.modify(name=new_name) - - @staticmethod - def _wrap_lun_list(lun_list): - if lun_list is not None: - ret = list(map(lambda lun: {'lun': lun}, lun_list)) - else: - ret = None - return ret - - @staticmethod - def _wrap_host_list(host_list, cli): - def make_host_elem(host): - return cli.make_body(host=host, - accessMask=enums.HostLUNAccessEnum.BOTH) - - if host_list is not None: - ret = list(map(make_host_elem, host_list)) - else: - ret = None - return ret - - def add_lun(self, *lun_list): - return self.modify(luns_to_add=lun_list) - - def remove_lun(self, *lun_list): - return self.modify(luns_to_remove=lun_list) - - def set_host_access(self, *hosts): - return self.modify(hosts=hosts) - - def add_host_access(self, *hosts): - return self.modify(hosts_to_add=hosts) - - def remove_host_access(self, *hosts): - return self.modify(hosts_to_remove=hosts) - - def create_snap(self, name=None, description=None, is_auto_delete=None, - retention_duration=None): - clz = storops.unity.resource.snap.UnitySnap - return clz.create(self._cli, self, name=name, description=description, - is_auto_delete=is_auto_delete, - retention_duration=retention_duration, - is_read_only=None, fs_access_type=None) - - @property - def snapshots(self): - clz = storops.unity.resource.snap.UnitySnapList - snaps = clz(cli=self._cli, storage_resource=self) - return list(filter(lambda snap: snap.snap_group is None, snaps)) - - def modify(self, name=None, description=None, - luns_to_add=None, luns_to_remove=None, - hosts_to_add=None, hosts_to_remove=None, hosts=None): - luns_to_add = self._wrap_lun_list(luns_to_add) - luns_to_remove = self._wrap_lun_list(luns_to_remove) - - hosts_to_add = self._wrap_host_list(hosts_to_add, self._cli) - hosts = self._wrap_host_list(hosts, self._cli) - - resp = self.action( - 'modifyConsistencyGroup', - name=name, description=description, - lunAdd=luns_to_add, lunRemove=luns_to_remove, - blockHostAccess=hosts, addBlockHostAccess=hosts_to_add, - removeBlockHostAccess=hosts_to_remove) - resp.raise_if_err() - return resp - - -class UnityConsistencyGroupList(UnityResourceList): - type_cg = enums.StorageResourceTypeEnum.CONSISTENCY_GROUP - - def __init__(self, **the_filter): - the_filter['type'] = self.type_cg - super(UnityConsistencyGroupList, self).__init__(**the_filter) - - @classmethod - def get_resource_class(cls): - return UnityConsistencyGroup - - def _filter(self, item): - return item.type == self.type_cg diff --git a/storops/unity/resource/system.py b/storops/unity/resource/system.py index 3e1cca88..fc8dd8be 100755 --- a/storops/unity/resource/system.py +++ b/storops/unity/resource/system.py @@ -47,7 +47,7 @@ UnitySasPortList, UnityIscsiNodeList from storops.unity.resource.snap import UnitySnapList from storops.unity.resource.sp import UnityStorageProcessorList -from storops.unity.resource.storage_resource import UnityConsistencyGroup, \ +from storops.unity.resource.cg import UnityConsistencyGroup, \ UnityConsistencyGroupList from storops.unity.resource.tenant import UnityTenant, UnityTenantList from storops.unity.resource.vmware import UnityCapabilityProfileList @@ -275,9 +275,9 @@ def get_cg(self, _id=None, name=None, **filters): return self._get_unity_rsc(UnityConsistencyGroupList, _id=_id, name=name, **filters) - def create_cg(self, name, description=None, lun_list=None, hosts=None): + def create_cg(self, name, description=None, lun_add=None, hosts=None): return UnityConsistencyGroup.create( - self._cli, name, description=description, lun_list=lun_list, + self._cli, name, description=description, lun_add=lun_add, hosts=hosts) def get_doc(self, resource): diff --git a/storops_test/unity/resource/test_cg.py b/storops_test/unity/resource/test_cg.py new file mode 100644 index 00000000..3d2d9a95 --- /dev/null +++ b/storops_test/unity/resource/test_cg.py @@ -0,0 +1,273 @@ +# Copyright (c) 2018 Dell Inc. or its subsidiaries. +# All Rights Reserved. +# +# 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. +from __future__ import unicode_literals + +from unittest import TestCase + +from hamcrest import assert_that, equal_to, instance_of, has_items, raises, \ + contains_string, none + +from storops.exception import UnityStorageResourceNameInUseError, \ + UnityConsistencyGroupNameInUseError, UnityResourceNotFoundError, \ + UnityNothingToModifyError, UnityHostAccessAlreadyExistsError +from storops.unity.enums import StorageResourceTypeEnum, HostLUNAccessEnum +from storops.unity.resource.cg import UnityConsistencyGroup, \ + UnityConsistencyGroupList + +from storops.unity.resource.host import UnityHost +from storops.unity.resource.lun import UnityLun +from storops.unity.resource.snap import UnitySnap + +from storops_test.unity.rest_mock import t_rest, patch_rest + + +__author__ = 'Peter Wang' + + +class UnityConsistencyGroupTest(TestCase): + cg_type = StorageResourceTypeEnum.CONSISTENCY_GROUP + + @staticmethod + def get_cg(): + return UnityConsistencyGroup(cli=t_rest(), _id='res_19') + + @patch_rest + def test_get_properties(self): + cg = UnityConsistencyGroup(_id='res_13', cli=t_rest()) + assert_that(cg.id, equal_to('res_13')) + assert_that(cg.type, equal_to(self.cg_type)) + + @patch_rest + def test_get_cg_list(self): + cg_list = UnityConsistencyGroupList(cli=t_rest()) + assert_that(len(cg_list), equal_to(2)) + for cg in cg_list: + assert_that(cg, instance_of(UnityConsistencyGroup)) + + @patch_rest + def test_create_empty_cg(self): + cg = UnityConsistencyGroup.create(t_rest(), 'Goddess') + assert_that(cg.name, equal_to('Goddess')) + assert_that(cg.type, equal_to(self.cg_type)) + + @patch_rest + def test_create_cg_with_initial_member(self): + lun1 = UnityLun(cli=t_rest(), _id='sv_3339') + lun2 = UnityLun(cli=t_rest(), _id='sv_3340') + cg = UnityConsistencyGroup.create(t_rest(), 'Muse', + lun_add=[lun1, lun2]) + assert_that(cg.name, equal_to('Muse')) + + members = cg.luns + assert_that(len(members), equal_to(2)) + lun_id_list = map(lambda lun: lun.get_id(), members) + assert_that(lun_id_list, has_items('sv_3339', 'sv_3340')) + + @patch_rest + def test_create_cg_with_hosts(self): + lun1 = UnityLun(cli=t_rest(), _id='sv_3338') + host1 = UnityHost(cli=t_rest(), _id='Host_14') + host2 = UnityHost(cli=t_rest(), _id='Host_15') + cg = UnityConsistencyGroup.create( + t_rest(), 'Muse', lun_add=[lun1], hosts=[host1, host2]) + hosts = cg.block_host_access + + assert_that(len(hosts), equal_to(2)) + for mask in hosts.access_mask: + assert_that(mask, equal_to(HostLUNAccessEnum.BOTH)) + + @patch_rest + def test_create_cg_name_in_use(self): + def f(): + UnityConsistencyGroup.create(t_rest(), 'in_use') + + assert_that(f, raises(UnityConsistencyGroupNameInUseError, 'used')) + + @patch_rest + def test_delete_cg_normal(self): + cg = UnityConsistencyGroup(cli=t_rest(), _id='res_18') + resp = cg.delete() + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_delete_cg_not_exists(self): + def f(): + cg = UnityConsistencyGroup(cli=t_rest(), _id='res_119') + cg.delete() + + assert_that(f, raises(UnityResourceNotFoundError, 'not exist')) + + @patch_rest + def test_rename_name_used(self): + def f(): + self.get_cg().name = 'iscsi-test' + + assert_that(f, raises(UnityStorageResourceNameInUseError, 'reserved')) + + @patch_rest + def test_add_lun_success(self): + lun1 = UnityLun(cli=t_rest(), _id='sv_3341') + lun2 = UnityLun(cli=t_rest(), _id='sv_3342') + resp = self.get_cg().add_lun(lun1, lun2) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_add_lun_nothing_to_modify(self): + def f(): + lun = UnityLun(cli=t_rest(), _id='sv_3341') + self.get_cg().add_lun(lun) + + assert_that(f, raises(UnityNothingToModifyError, 'nothing to modify')) + + @patch_rest + def test_remove_lun_success(self): + lun = UnityLun(cli=t_rest(), _id='sv_3342') + resp = self.get_cg().remove_lun(lun) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_remove_host_access(self): + host1 = UnityHost(cli=t_rest(), _id='Host_14') + host2 = UnityHost(cli=t_rest(), _id='Host_15') + resp = self.get_cg().remove_host_access(host1, host2) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_set_host_access(self): + host = UnityHost(cli=t_rest(), _id='Host_14') + resp = self.get_cg().set_host_access(host) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_add_host_access_existed(self): + def f(): + host1 = UnityHost(cli=t_rest(), _id='Host_14') + host2 = UnityHost(cli=t_rest(), _id='Host_15') + self.get_cg().add_host_access(host1, host2) + + assert_that(f, raises(UnityHostAccessAlreadyExistsError, 'has access')) + + @patch_rest + def test_add_host_access_success(self): + host1 = UnityHost(cli=t_rest(), _id='Host_12') + host2 = UnityHost(cli=t_rest(), _id='Host_15') + resp = self.get_cg().add_host_access(host1, host2) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_create_cg_snap(self): + snap = self.get_cg().create_snap('song') + assert_that(snap.name, equal_to('song')) + assert_that(snap.storage_resource.get_id(), equal_to('res_19')) + + @patch_rest + def test_list_cg_snaps(self): + snaps = self.get_cg().snapshots + assert_that(len(snaps), equal_to(2)) + assert_that(map(lambda s: s.name, snaps), has_items('song', 'tragedy')) + + @patch_rest + def test_detach_cg_snap(self): + snap = UnitySnap(cli=t_rest(), _id='85899345927') + host = UnityHost(cli=t_rest(), _id='Host_22') + resp = snap.detach_from(host) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_attach_cg_snap(self): + snap = UnitySnap(cli=t_rest(), _id='85899345927') + host = UnityHost(cli=t_rest(), _id='Host_22') + resp = snap.attach_to(host) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_restore_cg_snap_with_backup(self): + snap = UnitySnap(cli=t_rest(), _id='85899345927') + backup_snap = snap.restore('paint') + assert_that(backup_snap.name, equal_to('paint')) + assert_that(backup_snap.storage_resource.get_id(), equal_to('res_19')) + + @patch_rest + def test_restore_cg_snap_without_backup(self): + snap = UnitySnap(cli=t_rest(), _id='85899345927') + backup_snap = snap.restore() + assert_that(backup_snap.name, equal_to('2016-11-03_08.35.00')) + assert_that(backup_snap.storage_resource.get_id(), equal_to('res_19')) + + @patch_rest + def test_attach_lun_in_cg(self): + lun_in_cg = UnityLun.get(cli=t_rest(), _id='sv_15') + host = UnityHost(cli=t_rest(), _id='Host_22') + + resp = lun_in_cg.attach_to(host) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_detach_lun_in_cg(self): + lun_in_cg = UnityLun.get(cli=t_rest(), _id='sv_15') + host = UnityHost(cli=t_rest(), _id='Host_2') + + resp = lun_in_cg.detach_from(host) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_detach_lun_nothing(self): + lun_in_cg = UnityLun.get(cli=t_rest(), _id='sv_3') + host = UnityHost(cli=t_rest(), _id='Host_2') + + r = lun_in_cg.detach_from(host) + assert_that(r, none()) + + @patch_rest + def test_detach_lun_from_all(self): + lun_in_cg = UnityLun.get(cli=t_rest(), _id='sv_15') + resp = lun_in_cg.detach_from(None) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_expand_lun_in_cg(self): + lun_in_cg = UnityLun.get(cli=t_rest(), _id='sv_15') + old_size = lun_in_cg.size_total + resp = lun_in_cg.expand(100 * 1024 ** 3) + assert_that(resp, equal_to(old_size)) + + @patch_rest + def test_modify_lun_in_cg(self): + lun_in_cg = UnityLun.get(cli=t_rest(), _id='sv_15') + resp = lun_in_cg.modify(size=15 * 1024 ** 3) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_replace_lun_in_cg(self): + cg = UnityConsistencyGroup.get(cli=t_rest(), _id='res_6') + lun1 = UnityLun(cli=t_rest(), _id='sv_3341') + lun2 = UnityLun(cli=t_rest(), _id='sv_3342') + resp = cg.replace_lun(lun1, lun2) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_replace_lun_in_cg_already_in(self): + cg = UnityConsistencyGroup.get(cli=t_rest(), _id='res_6') + lun1 = UnityLun(cli=t_rest(), _id='sv_3341') + lun2 = UnityLun(cli=t_rest(), _id='sv_14') + resp = cg.replace_lun(lun1, lun2) + assert_that(resp.is_ok(), equal_to(True)) + + @patch_rest + def test_get_csv(self): + cg_list = UnityConsistencyGroupList(cli=t_rest()) + csv = cg_list.get_metrics_csv() + assert_that(csv, contains_string('id,name')) + assert_that(csv, contains_string('res_3,smis-test-cg')) diff --git a/storops_test/unity/resource/test_host.py b/storops_test/unity/resource/test_host.py index e9d5b80d..5697d0c7 100644 --- a/storops_test/unity/resource/test_host.py +++ b/storops_test/unity/resource/test_host.py @@ -410,6 +410,7 @@ def test_random_hlu_number_no_available(self): def test_attach_with_retry_skip_hlu_0(self): host = UnityHost(cli=t_rest(), _id='Host_23') lun = UnityLun(_id='sv_5610', cli=t_rest()) + lun.is_cg_member = False with mock.patch('storops.unity.resource.host.UnityHost.' '_random_hlu_number', new=lambda _: 12781): hlu = host._attach_with_retry(lun, True) @@ -420,18 +421,21 @@ def test_attach_with_retry_skip_hlu_0(self): def test_attach_with_retry_no_skip_hlu_0(self): host = UnityHost(cli=t_rest(), _id='Host_23') lun = UnityLun(_id='sv_5610', cli=t_rest()) + lun.is_cg_member = False assert_that(host._attach_with_retry(lun, False), equal_to(0)) @patch_rest def test_attach_with_retry_no_retry(self): host = UnityHost(cli=t_rest(), _id='Host_24') lun = UnityLun(_id='sv_5610', cli=t_rest()) + lun.is_cg_member = False assert_that(host._attach_with_retry(lun, True), equal_to(1)) @patch_rest def test_attach_with_retry_hlu_in_use(self): host = UnityHost(cli=t_rest(), _id='Host_23') lun = UnityLun(_id='sv_5610', cli=t_rest()) + lun.is_cg_member = False with mock.patch('storops.unity.resource.host.UnityHost.' '_modify_hlu', new=mock.Mock(side_effect=UnityHluNumberInUseError)): @@ -442,6 +446,7 @@ def test_attach_with_retry_hlu_in_use(self): def test_attach_with_retry_hlu_in_use_but_no_retry(self): host = UnityHost(cli=t_rest(), _id='Host_24') lun = UnityLun(_id='sv_5610', cli=t_rest()) + lun.is_cg_member = False with mock.patch('storops.unity.resource.host.UnityHost.' '_modify_hlu', new=mock.Mock(side_effect=UnityHluNumberInUseError)): @@ -451,6 +456,7 @@ def test_attach_with_retry_hlu_in_use_but_no_retry(self): def test_attach_with_retry_no_hlu_available(self): host = UnityHost(cli=t_rest(), _id='Host_23') lun = UnityLun(_id='sv_5610', cli=t_rest()) + lun.is_cg_member = False with mock.patch('storops.unity.resource.host.UnityHost.' '_random_hlu_number', new=mock.Mock(side_effect=UnityNoHluAvailableError)): @@ -476,6 +482,7 @@ def test_attach_exceptions(self): def test_attach_exceptions_detach(self): host = UnityHost(cli=t_rest(), _id='Host_25') lun = UnityLun(_id='sv_5611', cli=t_rest()) + lun.is_cg_member = False with mock.patch('storops.unity.resource.host.UnityHost.' '_attach_with_retry', new=mock.Mock(side_effect=UnityHluNumberInUseError)): @@ -491,6 +498,7 @@ def test_attach_exceptions_detach(self): def test_attach_exceptions_detach_dummy_lun(self): host = UnityHost(cli=t_rest(), _id='Host_26') lun = UnityLun(_id='sv_5611', cli=t_rest()) + lun.is_cg_member = False with mock.patch('storops.unity.resource.host.UnityHost.' '_attach_with_retry', new=mock.Mock(side_effect=UnityHluNumberInUseError)): @@ -504,12 +512,10 @@ def test_attach_exceptions_detach_dummy_lun(self): @patch_rest def test_attach_snap_skip_first_hlu(self): - def f(): - host = UnityHost(cli=t_rest(), _id='Host_11') - snap = UnitySnap(_id='38654705676', cli=t_rest()) - host.attach(snap, skip_hlu_0=True) - - assert_that(f, raises(UnitySnapAlreadyPromotedException)) + host = UnityHost(cli=t_rest(), _id='Host_11') + snap = UnitySnap(_id='38654705676', cli=t_rest()) + assert_that(calling(host.attach).with_args(snap, skip_hlu_0=True), + raises(UnitySnapAlreadyPromotedException)) @patch_rest def test_get_attached_cg_snap_hlu(self): diff --git a/storops_test/unity/resource/test_lun.py b/storops_test/unity/resource/test_lun.py index 2249ee6f..1aef3704 100644 --- a/storops_test/unity/resource/test_lun.py +++ b/storops_test/unity/resource/test_lun.py @@ -167,13 +167,14 @@ def test_lun_attach_to_same_host(self): @patch_rest def test_lun_detach_from_host(self): host = UnityHost(_id="Host_1", cli=t_rest()) - lun = UnityLun(_id='sv_4', cli=t_rest()) + lun = UnityLun(_id='sv_16', cli=t_rest()) resp = lun.detach_from(host) assert_that(resp.is_ok(), equal_to(True)) @patch_rest def test_lun_detach_from_all_hosts(self): lun = UnityLun(_id='sv_5', cli=t_rest()) + lun.is_cg_member = False resp = lun.detach_from(host=None) assert_that(resp.is_ok(), equal_to(True)) diff --git a/storops_test/unity/resource/test_storage_resource.py b/storops_test/unity/resource/test_storage_resource.py index 8e12f070..c6b4c932 100644 --- a/storops_test/unity/resource/test_storage_resource.py +++ b/storops_test/unity/resource/test_storage_resource.py @@ -17,22 +17,15 @@ from unittest import TestCase -from hamcrest import assert_that, equal_to, instance_of, has_items, raises, \ - contains_string +from hamcrest import assert_that, equal_to, instance_of -from storops.exception import UnityStorageResourceNameInUseError, \ - UnityConsistencyGroupNameInUseError, UnityResourceNotFoundError, \ - UnityNothingToModifyError, UnityHostAccessAlreadyExistsError from storops.unity.enums import StorageResourceTypeEnum, ReplicationTypeEnum, \ - ThinStatusEnum, TieringPolicyEnum, HostLUNAccessEnum + ThinStatusEnum, TieringPolicyEnum from storops.unity.resource.filesystem import UnityFileSystem from storops.unity.resource.health import UnityHealth -from storops.unity.resource.host import UnityHost -from storops.unity.resource.lun import UnityLun from storops.unity.resource.pool import UnityPoolList -from storops.unity.resource.snap import UnitySnap from storops.unity.resource.storage_resource import UnityStorageResource, \ - UnityStorageResourceList, UnityConsistencyGroup, UnityConsistencyGroupList + UnityStorageResourceList from storops_test.unity.rest_mock import t_rest, patch_rest __author__ = 'Cedric Zhuang' @@ -68,181 +61,3 @@ def test_get_properties(self): def test_get_all(self): sr_list = UnityStorageResourceList(cli=t_rest()) assert_that(len(sr_list), equal_to(10)) - - -class UnityConsistencyGroupTest(TestCase): - cg_type = StorageResourceTypeEnum.CONSISTENCY_GROUP - - @staticmethod - def get_cg(): - return UnityConsistencyGroup(cli=t_rest(), _id='res_19') - - @patch_rest - def test_get_properties(self): - cg = UnityConsistencyGroup(_id='res_13', cli=t_rest()) - assert_that(cg.id, equal_to('res_13')) - assert_that(cg.type, equal_to(self.cg_type)) - - @patch_rest - def test_get_cg_list(self): - cg_list = UnityConsistencyGroupList(cli=t_rest()) - assert_that(len(cg_list), equal_to(2)) - for cg in cg_list: - assert_that(cg, instance_of(UnityConsistencyGroup)) - - @patch_rest - def test_create_empty_cg(self): - cg = UnityConsistencyGroup.create(t_rest(), 'Goddess') - assert_that(cg.name, equal_to('Goddess')) - assert_that(cg.type, equal_to(self.cg_type)) - - @patch_rest - def test_create_cg_with_initial_member(self): - lun1 = UnityLun(cli=t_rest(), _id='sv_3339') - lun2 = UnityLun(cli=t_rest(), _id='sv_3340') - cg = UnityConsistencyGroup.create(t_rest(), 'Muse', - lun_list=[lun1, lun2]) - assert_that(cg.name, equal_to('Muse')) - - members = cg.luns - assert_that(len(members), equal_to(2)) - lun_id_list = map(lambda lun: lun.get_id(), members) - assert_that(lun_id_list, has_items('sv_3339', 'sv_3340')) - - @patch_rest - def test_create_cg_with_hosts(self): - lun1 = UnityLun(cli=t_rest(), _id='sv_3338') - host1 = UnityHost(cli=t_rest(), _id='Host_14') - host2 = UnityHost(cli=t_rest(), _id='Host_15') - cg = UnityConsistencyGroup.create( - t_rest(), 'Muse', lun_list=[lun1], hosts=[host1, host2]) - hosts = cg.block_host_access - - assert_that(len(hosts), equal_to(2)) - for mask in hosts.access_mask: - assert_that(mask, equal_to(HostLUNAccessEnum.BOTH)) - - @patch_rest - def test_create_cg_name_in_use(self): - def f(): - UnityConsistencyGroup.create(t_rest(), 'in_use') - - assert_that(f, raises(UnityConsistencyGroupNameInUseError, 'used')) - - @patch_rest - def test_delete_cg_normal(self): - cg = UnityConsistencyGroup(cli=t_rest(), _id='res_18') - resp = cg.delete() - assert_that(resp.is_ok(), equal_to(True)) - - @patch_rest - def test_delete_cg_not_exists(self): - def f(): - cg = UnityConsistencyGroup(cli=t_rest(), _id='res_119') - cg.delete() - - assert_that(f, raises(UnityResourceNotFoundError, 'not exist')) - - @patch_rest - def test_rename_name_used(self): - def f(): - self.get_cg().name = 'iscsi-test' - - assert_that(f, raises(UnityStorageResourceNameInUseError, 'reserved')) - - @patch_rest - def test_add_lun_success(self): - lun1 = UnityLun(cli=t_rest(), _id='sv_3341') - lun2 = UnityLun(cli=t_rest(), _id='sv_3342') - resp = self.get_cg().add_lun(lun1, lun2) - assert_that(resp.is_ok(), equal_to(True)) - - @patch_rest - def test_add_lun_nothing_to_modify(self): - def f(): - lun = UnityLun(cli=t_rest(), _id='sv_3341') - self.get_cg().add_lun(lun) - - assert_that(f, raises(UnityNothingToModifyError, 'nothing to modify')) - - @patch_rest - def test_remove_lun_success(self): - lun = UnityLun(cli=t_rest(), _id='sv_3342') - resp = self.get_cg().remove_lun(lun) - assert_that(resp.is_ok(), equal_to(True)) - - @patch_rest - def test_remove_host_access(self): - host1 = UnityHost(cli=t_rest(), _id='Host_14') - host2 = UnityHost(cli=t_rest(), _id='Host_15') - resp = self.get_cg().remove_host_access(host1, host2) - assert_that(resp.is_ok(), equal_to(True)) - - @patch_rest - def test_set_host_access(self): - host = UnityHost(cli=t_rest(), _id='Host_14') - resp = self.get_cg().set_host_access(host) - assert_that(resp.is_ok(), equal_to(True)) - - @patch_rest - def test_add_host_access_existed(self): - def f(): - host1 = UnityHost(cli=t_rest(), _id='Host_14') - host2 = UnityHost(cli=t_rest(), _id='Host_15') - self.get_cg().add_host_access(host1, host2) - - assert_that(f, raises(UnityHostAccessAlreadyExistsError, 'has access')) - - @patch_rest - def test_add_host_access_success(self): - host1 = UnityHost(cli=t_rest(), _id='Host_12') - host2 = UnityHost(cli=t_rest(), _id='Host_15') - resp = self.get_cg().add_host_access(host1, host2) - assert_that(resp.is_ok(), equal_to(True)) - - @patch_rest - def test_create_cg_snap(self): - snap = self.get_cg().create_snap('song') - assert_that(snap.name, equal_to('song')) - assert_that(snap.storage_resource.get_id(), equal_to('res_19')) - - @patch_rest - def test_list_cg_snaps(self): - snaps = self.get_cg().snapshots - assert_that(len(snaps), equal_to(2)) - assert_that(map(lambda s: s.name, snaps), has_items('song', 'tragedy')) - - @patch_rest - def test_detach_cg_snap(self): - snap = UnitySnap(cli=t_rest(), _id='85899345927') - host = UnityHost(cli=t_rest(), _id='Host_22') - resp = snap.detach_from(host) - assert_that(resp.is_ok(), equal_to(True)) - - @patch_rest - def test_attach_cg_snap(self): - snap = UnitySnap(cli=t_rest(), _id='85899345927') - host = UnityHost(cli=t_rest(), _id='Host_22') - resp = snap.attach_to(host) - assert_that(resp.is_ok(), equal_to(True)) - - @patch_rest - def test_restore_cg_snap_with_backup(self): - snap = UnitySnap(cli=t_rest(), _id='85899345927') - backup_snap = snap.restore('paint') - assert_that(backup_snap.name, equal_to('paint')) - assert_that(backup_snap.storage_resource.get_id(), equal_to('res_19')) - - @patch_rest - def test_restore_cg_snap_without_backup(self): - snap = UnitySnap(cli=t_rest(), _id='85899345927') - backup_snap = snap.restore() - assert_that(backup_snap.name, equal_to('2016-11-03_08.35.00')) - assert_that(backup_snap.storage_resource.get_id(), equal_to('res_19')) - - @patch_rest - def test_get_csv(self): - cg_list = UnityConsistencyGroupList(cli=t_rest()) - csv = cg_list.get_metrics_csv() - assert_that(csv, contains_string('id,name')) - assert_that(csv, contains_string('res_3,smis-test-cg')) diff --git a/storops_test/unity/resource/test_system.py b/storops_test/unity/resource/test_system.py index e58f6597..1d51a1a3 100644 --- a/storops_test/unity/resource/test_system.py +++ b/storops_test/unity/resource/test_system.py @@ -494,7 +494,7 @@ def test_create_cg(self): lun1 = UnityLun(cli=t_rest(), _id='sv_3339') lun2 = UnityLun(cli=t_rest(), _id='sv_3340') unity = t_unity() - cg = unity.create_cg('Muse', lun_list=[lun1, lun2]) + cg = unity.create_cg('Muse', lun_add=[lun1, lun2]) assert_that(cg.name, equal_to('Muse')) assert_that(len(cg.luns), equal_to(2)) diff --git a/storops_test/unity/rest_data/cifsShare/index.json b/storops_test/unity/rest_data/cifsShare/index.json index b7cb407b..e5f7aee9 100644 --- a/storops_test/unity/rest_data/cifsShare/index.json +++ b/storops_test/unity/rest_data/cifsShare/index.json @@ -45,7 +45,6 @@ }, { "url": "/api/instances/cifsShare/SMBShare_15?compact=True", - "body": {}, "response": "success.json" }, { diff --git a/storops_test/unity/rest_data/host/host_14.json b/storops_test/unity/rest_data/host/host_14.json new file mode 100644 index 00000000..ddda3e43 --- /dev/null +++ b/storops_test/unity/rest_data/host/host_14.json @@ -0,0 +1,26 @@ +{ + "content": { + "id": "Host_14", + "operationalStatus": [ + 2 + ], + "type": 1, + "autoManageType": 0, + "instanceId": "root/emc:EMC_UEM_HostLeaf%InstanceID=Host_14", + "health": { + "value": 5, + "descriptionIds": [ + "ALRT_COMPONENT_OK" + ], + "descriptions": [ + "The component is operating normally. No action is required." + ] + }, + "tenant": { + "id": "tenant_4" + }, + "name": "host14", + "description": "", + "osType": "RHEL" + } +} \ No newline at end of file diff --git a/storops_test/unity/rest_data/host/host_2.json b/storops_test/unity/rest_data/host/host_2.json new file mode 100644 index 00000000..c4505a6e --- /dev/null +++ b/storops_test/unity/rest_data/host/host_2.json @@ -0,0 +1,95 @@ +{ + "content": { + "id": "Host_2", + "operationalStatus": [ + 2 + ], + "type": 5, + "autoManageType": 1, + "instanceId": "root/emc:EMC_UEM_HostLeaf%InstanceID=Host_1", + "health": { + "value": 5, + "descriptionIds": [ + "ALRT_COMPONENT_OK" + ], + "descriptions": [ + "The component is operating normally. No action is required." + ] + }, + "name": "10.244.209.90", + "description": "", + "osType": "VMware ESXi 6.0.0", + "hostPushedUUID": "5322a3d1-2901-08c3-c39f-f80f41fafe2e", + "hostPolledUUID": "rfc4122.cd9f4de2-78a5-11e3-85bd-f80f41fafe2e", + "lastPollTime": "2016-03-03T04:40:13.000Z", + "hostContainer": { + "id": "mss_1" + }, + "iscsiHostInitiators": [ + { + "id": "HostInitiator_1", + "initiatorId": "50:00:14:40:47:B0:0C:44:50:00:14:42:D0:0C:44:10" + } + ], + "hostIPPorts": [ + { + "id": "HostNetworkAddress_1" + } + ], + "datastores": [ + { + "id": "rfc4122.cd9f4de2-78a5-11e3-85bd-f80f41fafe2e_ds:///vmfs/volumes/564cf41c-fc332453-32a8-f80f41fafe2e/" + }, + { + "id": "rfc4122.cd9f4de2-78a5-11e3-85bd-f80f41fafe2e_ds:///vmfs/volumes/5322a4d4-728ccd94-8dc2-f80f41fafe2e/" + }, + { + "id": "rfc4122.cd9f4de2-78a5-11e3-85bd-f80f41fafe2e_ds:///vmfs/volumes/75df1b51-9c9b37af/" + } + ], + "vms": [ + { + "id": "503e0a21-67c3-11c6-4100-eca1a1b3dca3" + }, + { + "id": "503e33de-3748-ef18-ce4f-5a75cf5c56fc" + }, + { + "id": "503e37d0-aaab-05e2-5658-2b601b9ed545" + }, + { + "id": "503e4dae-89e3-ac14-d15e-27cec81b5edd" + }, + { + "id": "503e5625-1dcb-5a86-163c-6c44c9f7a613" + }, + { + "id": "503e729d-5fd5-307a-015d-33dcc3ddd353" + }, + { + "id": "503e7b9e-a998-adc3-d1f2-ef7572a9282e" + }, + { + "id": "503e9236-35e5-a29c-2484-19a6b7a591ce" + }, + { + "id": "503e9d4b-dcd2-58e4-39cf-4952a03aba04" + }, + { + "id": "503ee342-17e6-c873-c8b2-3855f8f12f9a" + }, + { + "id": "503ee745-0f3e-bd7a-a07a-0a680febbdbb" + }, + { + "id": "5271b28c-d0f7-856e-af81-77d42c88d67a" + }, + { + "id": "503efcd0-58d0-b635-86bf-402226a30eec" + }, + { + "id": "503e12de-cc11-2281-e225-d03a002754bc" + } + ] + } +} \ No newline at end of file diff --git a/storops_test/unity/rest_data/host/index.json b/storops_test/unity/rest_data/host/index.json index 8729e950..f855cd8c 100644 --- a/storops_test/unity/rest_data/host/index.json +++ b/storops_test/unity/rest_data/host/index.json @@ -119,6 +119,10 @@ "url": "/api/instances/host/Host_1?compact=True", "response": "empty.json" }, + { + "url": "/api/instances/host/Host_2?compact=True&fields=autoManageType,datastores,description,fcHostInitiators,fcHostInitiators.initiatorId,fcHostInitiators.paths.fcPort.wwn,fcHostInitiators.paths.initiator.type,fcHostInitiators.paths.isLoggedIn,health,hostContainer,hostIPPorts,hostIPPorts.address,hostLUNs,hostLUNs.hlu,hostLUNs.lun.id,hostLUNs.lun.name,hostLUNs.snap.id,hostPolledUUID,hostPushedUUID,hostUUID,hostVVolDatastore,id,instanceId,isInitializationComplete,iscsiHostInitiators,iscsiHostInitiators.initiatorId,lastPollTime,name,nfsShareAccesses,operationalStatus,osType,registrationType,storageResources,type,vms", + "response": "host_2.json" + }, { "url": "/api/instances/host/Host_12?compact=True&fields=autoManageType,datastores,description,fcHostInitiators,fcHostInitiators.initiatorId,fcHostInitiators.paths.fcPort.wwn,fcHostInitiators.paths.initiator.type,fcHostInitiators.paths.isLoggedIn,health,hostContainer,hostIPPorts,hostIPPorts.address,hostLUNs,hostLUNs.hlu,hostLUNs.lun.id,hostLUNs.lun.name,hostLUNs.snap.id,hostPolledUUID,hostPushedUUID,hostUUID,hostVVolDatastore,id,instanceId,isInitializationComplete,iscsiHostInitiators,iscsiHostInitiators.initiatorId,lastPollTime,name,nfsShareAccesses,operationalStatus,osType,registrationType,storageResources,type,vms", "response": "host_12.json" @@ -126,6 +130,10 @@ { "url": "/api/instances/host/Host_13?compact=True&fields=autoManageType,datastores,description,fcHostInitiators,fcHostInitiators.initiatorId,fcHostInitiators.paths.fcPort.wwn,fcHostInitiators.paths.initiator.type,fcHostInitiators.paths.isLoggedIn,health,hostContainer,hostIPPorts,hostIPPorts.address,hostLUNs,hostLUNs.hlu,hostLUNs.lun.id,hostLUNs.lun.name,hostLUNs.snap.id,hostPolledUUID,hostPushedUUID,hostUUID,hostVVolDatastore,id,instanceId,isInitializationComplete,iscsiHostInitiators,iscsiHostInitiators.initiatorId,lastPollTime,name,nfsShareAccesses,operationalStatus,osType,registrationType,storageResources,type,vms", "response": "host_13.json" + }, + { + "url": "/api/instances/host/Host_14?compact=True&fields=autoManageType,datastores,description,fcHostInitiators,fcHostInitiators.initiatorId,fcHostInitiators.paths.fcPort.wwn,fcHostInitiators.paths.initiator.type,fcHostInitiators.paths.isLoggedIn,health,hostContainer,hostIPPorts,hostIPPorts.address,hostLUNs,hostLUNs.hlu,hostLUNs.lun.id,hostLUNs.lun.name,hostLUNs.snap.id,hostPolledUUID,hostPushedUUID,hostUUID,hostVVolDatastore,id,instanceId,isInitializationComplete,iscsiHostInitiators,iscsiHostInitiators.initiatorId,lastPollTime,name,nfsShareAccesses,operationalStatus,osType,registrationType,storageResources,type,vms", + "response": "host_14.json" }, { "url": "/api/instances/host/Host_15?compact=True&fields=autoManageType,datastores,description,fcHostInitiators,fcHostInitiators.initiatorId,fcHostInitiators.paths.fcPort.wwn,fcHostInitiators.paths.initiator.type,fcHostInitiators.paths.isLoggedIn,health,hostContainer,hostIPPorts,hostIPPorts.address,hostLUNs,hostLUNs.hlu,hostLUNs.lun.id,hostLUNs.lun.name,hostLUNs.snap.id,hostPolledUUID,hostPushedUUID,hostUUID,hostVVolDatastore,id,instanceId,isInitializationComplete,iscsiHostInitiators,iscsiHostInitiators.initiatorId,lastPollTime,name,nfsShareAccesses,operationalStatus,osType,registrationType,storageResources,type,vms", diff --git a/storops_test/unity/rest_data/lun/index.json b/storops_test/unity/rest_data/lun/index.json index 0d677da9..dbc88975 100644 --- a/storops_test/unity/rest_data/lun/index.json +++ b/storops_test/unity/rest_data/lun/index.json @@ -5,31 +5,31 @@ "response": "type.json" }, { - "url": "/api/instances/lun/sv_2?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_2?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_2.json" }, { - "url": "/api/instances/lun/sv_3?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_3?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_3.json" }, { - "url": "/api/instances/lun/sv_4678?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_4678?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_4678.json" }, { - "url": "/api/instances/lun/sv_567?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_567?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_567.json" }, { - "url": "/api/instances/lun/sv_4?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_4?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_4.json" }, { - "url": "/api/instances/lun/sv_5?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5.json" }, { - "url": "/api/instances/lun/sv_3338?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_3338?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_3338.json" }, { @@ -37,111 +37,119 @@ "response": "for_test.json" }, { - "url": "/api/types/lun/instances?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/types/lun/instances?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "all.json" }, { - "url": "/api/types/lun/instances?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn&filter=name eq \"openstack_lun\"", + "url": "/api/types/lun/instances?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn&filter=name eq \"openstack_lun\"", "response": "sv_2.json" }, { - "url": "/api/types/lun/instances?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn&filter=name eq \"LunName\"", + "url": "/api/types/lun/instances?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn&filter=name eq \"LunName\"", "response": "search_fail.json" }, { - "url": "/api/instances/lun/sv_8?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_8?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_8.json" }, { - "url": "/api/instances/lun/sv_9?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_9?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_9.json" }, { - "url": "/api/instances/lun/sv_10?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_10?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_10.json" }, { - "url": "/api/instances/lun/sv_11?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_11?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_11.json" }, { - "url": "/api/instances/lun/sv_12?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_12?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_12.json" }, { - "url": "/api/instances/lun/sv_2019?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_15?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", + "response": "sv_15.json" + }, + { + "url": "/api/instances/lun/sv_16?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", + "response": "sv_16.json" + }, + { + "url": "/api/instances/lun/sv_2019?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_2019.json" }, { - "url": "/api/instances/lun/sv_2026?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_2026?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_2026.json" }, { - "url": "/api/types/lun/instances?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn&filter=name eq \"storops_dummy_lun\"", + "url": "/api/types/lun/instances?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn&filter=name eq \"storops_dummy_lun\"", "response": "not_found.json" }, { - "url": "/api/instances/lun/sv_5555?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5555?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5555.json" }, { - "url": "/api/instances/lun/sv_5556?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5556?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5556.json" }, { - "url": "/api/instances/lun/sv_5557?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5557?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5557.json" }, { - "url": "/api/instances/lun/sv_5600?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5600?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5600.json" }, { - "url": "/api/instances/lun/sv_5601?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5601?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5601.json" }, { - "url": "/api/instances/lun/sv_5602?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5602?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5602.json" }, { - "url": "/api/instances/lun/sv_5603?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5603?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5603.json" }, { - "url": "/api/instances/lun/sv_5604?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5604?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5604.json" }, { - "url": "/api/instances/lun/sv_5605?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5605?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5605.json" }, { - "url": "/api/instances/lun/sv_5606?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5606?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5606.json" }, { - "url": "/api/instances/lun/sv_5607?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5607?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5607.json" }, { - "url": "/api/instances/lun/sv_5608?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5608?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5608.json" }, { - "url": "/api/instances/lun/sv_5609?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5609?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5609.json" }, { - "url": "/api/instances/lun/sv_5610?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5610?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5610.json" }, { - "url": "/api/instances/lun/sv_5611?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5611?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5611.json" }, { - "url": "/api/instances/lun/sv_5612?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,tieringPolicy,type,wwn", + "url": "/api/instances/lun/sv_5612?compact=True&fields=auSize,creationTime,currentNode,defaultNode,description,health,hostAccess,hostAccess.host.name,id,instanceId,ioLimitPolicy,isReplicationDestination,isSnapSchedulePaused,isThinEnabled,lunGroupObjectId,metadataSize,metadataSizeAllocated,modificationTime,name,objectId,operationalStatus,perTierSizeUsed,pool,pool.isFASTCacheEnabled,pool.raidType,sizeAllocated,sizeTotal,sizeUsed,smpBackendId,snapCount,snapSchedule,snapWwn,snapsSize,snapsSizeAllocated,storageResource,storageResource.type,tieringPolicy,type,wwn", "response": "sv_5612.json" } ] diff --git a/storops_test/unity/rest_data/lun/sv_15.json b/storops_test/unity/rest_data/lun/sv_15.json new file mode 100644 index 00000000..c303818d --- /dev/null +++ b/storops_test/unity/rest_data/lun/sv_15.json @@ -0,0 +1,75 @@ +{ + "@base": "https://10.245.101.39/api/instances/lun", + "updated": "2018-05-07T02:59:46.982Z", + "links": [ + { + "rel": "self", + "href": "/sv_15" + } + ], + "content": { + "id": "sv_15", + "operationalStatus": [ + 2 + ], + "type": 1, + "tieringPolicy": 0, + "defaultNode": 1, + "currentNode": 1, + "auSize": 8192, + "instanceId": "root/emc:EMC_UEM_StorageVolumeLeaf%InstanceID=sv_15", + "creationTime": "2018-04-26T07:02:26.000Z", + "health": { + "value": 5, + "descriptionIds": [ + "ALRT_VOL_OK" + ], + "descriptions": [ + "The LUN is operating normally. No action is required." + ] + }, + "name": "lun-cg-liangr2-01", + "description": "", + "modificationTime": "2018-04-26T07:02:27.454Z", + "sizeTotal": 42949672960, + "sizeAllocated": 0, + "perTierSizeUsed": [ + 0, + 3221225472, + 0 + ], + "isThinEnabled": true, + "wwn": "60:06:01:60:15:E0:3A:00:81:79:E1:5A:5D:80:F5:93", + "isReplicationDestination": false, + "isSnapSchedulePaused": false, + "objectId": 42949672989, + "lunGroupObjectId": 81604378635, + "metadataSize": 3758096384, + "metadataSizeAllocated": 2684354560, + "snapWwn": "60:06:01:60:15:E0:3A:00:63:B9:1E:2C:39:4E:44:1D", + "snapsSize": 0, + "snapsSizeAllocated": 0, + "hostAccess": [ + { + "accessMask": 1, + "productionAccess": 1, + "snapshotAccess": 0, + "instanceId": "root/emc:EMC_UEM_HostAccessLunAssocLeaf%InstanceID=6", + "host": { + "id": "Host_2", + "name": "umsg.lab.emc.com" + } + } + ], + "snapCount": 0, + "storageResource": { + "id": "res_4", + "type": 2 + }, + "pool": { + "id": "pool_2", + "raidType": 1, + "isFASTCacheEnabled": false + } + } +} \ No newline at end of file diff --git a/storops_test/unity/rest_data/lun/sv_16.json b/storops_test/unity/rest_data/lun/sv_16.json new file mode 100644 index 00000000..f9618864 --- /dev/null +++ b/storops_test/unity/rest_data/lun/sv_16.json @@ -0,0 +1,71 @@ +{ + "@base": "https://10.245.101.39/api/instances/lun", + "updated": "2018-05-07T02:59:46.982Z", + "links": [ + { + "rel": "self", + "href": "/sv_16" + } + ], + "content": { + "id": "sv_16", + "operationalStatus": [ + 2 + ], + "type": 1, + "tieringPolicy": 0, + "defaultNode": 1, + "currentNode": 1, + "auSize": 8192, + "instanceId": "root/emc:EMC_UEM_StorageVolumeLeaf%InstanceID=sv_16", + "creationTime": "2018-04-26T07:02:26.000Z", + "health": { + "value": 5, + "descriptionIds": [ + "ALRT_VOL_OK" + ], + "descriptions": [ + "The LUN is operating normally. No action is required." + ] + }, + "name": "lun-cg-liangr2-01", + "description": "", + "modificationTime": "2018-04-26T07:02:27.454Z", + "sizeTotal": 42949672960, + "sizeAllocated": 0, + "perTierSizeUsed": [ + 0, + 3221225472, + 0 + ], + "isThinEnabled": true, + "wwn": "60:06:01:60:15:E0:3A:00:81:79:E1:5A:5D:80:F5:93", + "isReplicationDestination": false, + "isSnapSchedulePaused": false, + "objectId": 42949672989, + "lunGroupObjectId": 81604378635, + "metadataSize": 3758096384, + "metadataSizeAllocated": 2684354560, + "snapWwn": "60:06:01:60:15:E0:3A:00:63:B9:1E:2C:39:4E:44:1D", + "snapsSize": 0, + "snapsSizeAllocated": 0, + "snapCount": 0, + "hostAccess": [ + { + "accessMask": 3, + "instanceId": "root/emc:EMC_UEM_HostAccessLunAssocLeaf%InstanceID=544", + "host": { + "id": "Host_1" + } + } + ], + "storageResource": { + "id": "sv_16" + }, + "pool": { + "id": "pool_2", + "raidType": 1, + "isFASTCacheEnabled": false + } + } +} \ No newline at end of file diff --git a/storops_test/unity/rest_data/lun/sv_3.json b/storops_test/unity/rest_data/lun/sv_3.json index f3412947..9897ac73 100644 --- a/storops_test/unity/rest_data/lun/sv_3.json +++ b/storops_test/unity/rest_data/lun/sv_3.json @@ -43,7 +43,7 @@ "snapsSizeAllocated": 0, "snapCount": 0, "storageResource": { - "id": "res_2" + "id": "res_3" }, "pool": { "id": "pool_1" diff --git a/storops_test/unity/rest_data/nfsShare/index.json b/storops_test/unity/rest_data/nfsShare/index.json index 358bd22e..c169d63c 100644 --- a/storops_test/unity/rest_data/nfsShare/index.json +++ b/storops_test/unity/rest_data/nfsShare/index.json @@ -76,7 +76,6 @@ }, { "url": "/api/instances/nfsShare/NFSShare_11?compact=True", - "body": {}, "response": "success.json" }, { diff --git a/storops_test/unity/rest_data/snap/index.json b/storops_test/unity/rest_data/snap/index.json index 10907732..7997d96f 100644 --- a/storops_test/unity/rest_data/snap/index.json +++ b/storops_test/unity/rest_data/snap/index.json @@ -279,6 +279,7 @@ }, { "url": "/api/instances/snap/38654705676/action/detach?compact=True", + "body": {}, "response": "success.json" }, { @@ -321,10 +322,12 @@ }, { "url": "/api/instances/snap/85899345927/action/detach?compact=True", + "body": {}, "response": "success.json" }, { "url": "/api/instances/snap/85899345927/action/restore?compact=True", + "body": {}, "response": "restore_without_backup.json" }, { diff --git a/storops_test/unity/rest_data/storageResource/index.json b/storops_test/unity/rest_data/storageResource/index.json index a694eecd..de1fcbd4 100644 --- a/storops_test/unity/rest_data/storageResource/index.json +++ b/storops_test/unity/rest_data/storageResource/index.json @@ -16,6 +16,14 @@ "url": "/api/instances/storageResource/sv_2?compact=True&fields=blockHostAccess,datastores,dedupStatus,description,esxFilesystemBlockSize,esxFilesystemMajorVersion,filesystem,health,hostVVolDatastore,id,isReplicationDestination,isSnapSchedulePaused,luns,metadataSize,metadataSizeAllocated,name,perTierSizeUsed,pools,relocationPolicy,replicationType,sizeAllocated,sizeTotal,sizeUsed,snapCount,snapSchedule,snapsSizeAllocated,snapsSizeTotal,thinStatus,type,virtualVolumes,vmwareUUID", "response": "sv_2.json" }, + { + "url": "/api/instances/storageResource/sv_4?compact=True&fields=blockHostAccess,datastores,dedupStatus,description,esxFilesystemBlockSize,esxFilesystemMajorVersion,filesystem,health,hostVVolDatastore,id,isReplicationDestination,isSnapSchedulePaused,luns,metadataSize,metadataSizeAllocated,name,perTierSizeUsed,pools,relocationPolicy,replicationType,sizeAllocated,sizeTotal,sizeUsed,snapCount,snapSchedule,snapsSizeAllocated,snapsSizeTotal,thinStatus,type,virtualVolumes,vmwareUUID", + "response": "sv_4.json" + }, + { + "url": "/api/instances/storageResource/sv_16?compact=True&fields=blockHostAccess,datastores,dedupStatus,description,esxFilesystemBlockSize,esxFilesystemMajorVersion,filesystem,health,hostVVolDatastore,id,isReplicationDestination,isSnapSchedulePaused,luns,metadataSize,metadataSizeAllocated,name,perTierSizeUsed,pools,relocationPolicy,replicationType,sizeAllocated,sizeTotal,sizeUsed,snapCount,snapSchedule,snapsSizeAllocated,snapsSizeTotal,thinStatus,type,virtualVolumes,vmwareUUID", + "response": "sv_16.json" + }, { "url": "/api/instances/storageResource/res_3?compact=True&fields=blockHostAccess,datastores,dedupStatus,description,esxFilesystemBlockSize,esxFilesystemMajorVersion,filesystem,health,hostVVolDatastore,id,isReplicationDestination,isSnapSchedulePaused,luns,metadataSize,metadataSizeAllocated,name,perTierSizeUsed,pools,relocationPolicy,replicationType,sizeAllocated,sizeTotal,sizeUsed,snapCount,snapSchedule,snapsSizeAllocated,snapsSizeTotal,thinStatus,type,virtualVolumes,vmwareUUID", "response": "res_3.json" @@ -24,6 +32,10 @@ "url": "/api/instances/storageResource/res_4?compact=True&fields=blockHostAccess,datastores,dedupStatus,description,esxFilesystemBlockSize,esxFilesystemMajorVersion,filesystem,health,hostVVolDatastore,id,isReplicationDestination,isSnapSchedulePaused,luns,metadataSize,metadataSizeAllocated,name,perTierSizeUsed,pools,relocationPolicy,replicationType,sizeAllocated,sizeTotal,sizeUsed,snapCount,snapSchedule,snapsSizeAllocated,snapsSizeTotal,thinStatus,type,virtualVolumes,vmwareUUID", "response": "res_4.json" }, + { + "url": "/api/instances/storageResource/res_6?compact=True&fields=blockHostAccess,datastores,dedupStatus,description,esxFilesystemBlockSize,esxFilesystemMajorVersion,filesystem,health,hostVVolDatastore,id,isReplicationDestination,isSnapSchedulePaused,luns,metadataSize,metadataSizeAllocated,name,perTierSizeUsed,pools,relocationPolicy,replicationType,sizeAllocated,sizeTotal,sizeUsed,snapCount,snapSchedule,snapsSizeAllocated,snapsSizeTotal,thinStatus,type,virtualVolumes,vmwareUUID", + "response": "res_6.json" + }, { "url": "/api/instances/storageResource/res_13?compact=True&fields=blockHostAccess,datastores,dedupStatus,description,esxFilesystemBlockSize,esxFilesystemMajorVersion,filesystem,health,hostVVolDatastore,id,isReplicationDestination,isSnapSchedulePaused,luns,metadataSize,metadataSizeAllocated,name,perTierSizeUsed,pools,relocationPolicy,replicationType,sizeAllocated,sizeTotal,sizeUsed,snapCount,snapSchedule,snapsSizeAllocated,snapsSizeTotal,thinStatus,type,virtualVolumes,vmwareUUID", "response": "res_13.json" @@ -1048,6 +1060,11 @@ "body": {"lunParameters": {"hostAccess": []}}, "response": "empty.json" }, + { + "url": "/api/instances/storageResource/sv_16/action/modifyLun?compact=True", + "body": {"lunParameters": {"hostAccess": []}}, + "response": "empty.json" + }, { "url": "/api/instances/storageResource/sv_5609/action/modifyLun?compact=True", "body": {"lunParameters": {"hostAccess": [{"host": {"id": "Host_23"}, "accessMask": 1}]}}, @@ -1080,6 +1097,36 @@ "forceVvolDeletion": false }, "response": "empty.json" + }, + { + "url": "/api/instances/storageResource/res_4/action/modifyConsistencyGroup?compact=True", + "body": {"lunModify": [{"lunParameters": {"hostAccess": [{"host": {"id": "Host_22"}, "accessMask": 1}, {"host": {"id": "Host_2"}, "accessMask": 1}]}, "lun": {"id": "sv_15"}}]}, + "response": "empty.json" + }, + { + "url": "/api/instances/storageResource/res_4/action/modifyConsistencyGroup?compact=True", + "body": {"lunModify": [{"lun": {"id": "sv_15"}, "lunParameters": {"hostAccess": []}}]}, + "response": "empty.json" + }, + { + "url": "/api/instances/storageResource/res_4/action/modifyConsistencyGroup?compact=True", + "body": {"lunModify": [{"lun": {"id": "sv_15"}, "lunParameters": {"size": 107374182400}}]}, + "response": "empty.json" + }, + { + "url": "/api/instances/storageResource/res_4/action/modifyConsistencyGroup?compact=True", + "body": {"lunModify": [{"lun": {"id": "sv_15"}, "lunParameters": {"size": 16106127360}}]}, + "response": "empty.json" + }, + { + "url": "/api/instances/storageResource/res_6/action/modifyConsistencyGroup?compact=True", + "body": {"lunRemove": [{"lun": {"id": "sv_14"}}, {"lun": {"id": "sv_15"}}], "lunAdd": [{"lun": {"id": "sv_3342"}}, {"lun": {"id": "sv_3341"}}]}, + "response": "empty.json" + }, + { + "url": "/api/instances/storageResource/res_6/action/modifyConsistencyGroup?compact=True", + "body": {"lunRemove": [{"lun": {"id": "sv_15"}}], "lunAdd": [{"lun": {"id": "sv_3341"}}]}, + "response": "empty.json" } ] } diff --git a/storops_test/unity/rest_data/storageResource/res_6.json b/storops_test/unity/rest_data/storageResource/res_6.json new file mode 100644 index 00000000..e8e82bad --- /dev/null +++ b/storops_test/unity/rest_data/storageResource/res_6.json @@ -0,0 +1,74 @@ +{ + "@base": "https://10.245.101.39/api/instances/storageResource", + "updated": "2018-05-07T09:48:57.880Z", + "links": [ + { + "rel": "self", + "href": "/res_6" + } + ], + "content": { + "id": "res_6", + "type": 2, + "replicationType": 0, + "thinStatus": 1, + "relocationPolicy": 0, + "health": { + "value": 5, + "descriptionIds": [ + "ALRT_COMPONENT_OK" + ], + "descriptions": [ + "The component is operating normally. No action is required." + ] + }, + "name": "cg-2", + "description": "", + "isReplicationDestination": false, + "sizeTotal": 85899345920, + "sizeAllocated": 0, + "perTierSizeUsed": [ + 0, + 6442450944, + 0 + ], + "blockHostAccess": [ + { + "accessMask": 65535, + "productionAccess": 2, + "snapshotAccess": 0, + "instanceId": "root/emc:EMC_UIS_UEM_BlockHostAccessLeaf%InstanceID=1", + "host": { + "id": "Host_5" + } + }, + { + "accessMask": 1, + "productionAccess": 1, + "snapshotAccess": 0, + "instanceId": "root/emc:EMC_UIS_UEM_BlockHostAccessLeaf%InstanceID=2", + "host": { + "id": "Host_2" + } + } + ], + "metadataSize": 7516192768, + "metadataSizeAllocated": 5368709120, + "snapsSizeTotal": 0, + "snapsSizeAllocated": 0, + "snapCount": 0, + "pools": [ + { + "id": "pool_2" + } + ], + "luns": [ + { + "id": "sv_15" + }, + { + "id": "sv_14" + } + ] + } +} \ No newline at end of file diff --git a/storops_test/unity/rest_data/storageResource/sv_16.json b/storops_test/unity/rest_data/storageResource/sv_16.json new file mode 100644 index 00000000..e69de29b diff --git a/storops_test/unity/rest_mock.py b/storops_test/unity/rest_mock.py index a3896c0f..144c78ea 100644 --- a/storops_test/unity/rest_mock.py +++ b/storops_test/unity/rest_mock.py @@ -90,7 +90,7 @@ def get_filename(cls, inputs): for index in indices.get('indices', []): if url.lower() != index['url'].lower(): continue - elif body and body != index.get('body', None): + elif not cls.compare_json_body(body, index.get('body', None)): continue response = index['response'] break @@ -106,7 +106,7 @@ def read_index(folder): return json.loads(string_indices, encoding='utf-8') def _get_mock_output(self, url, kwargs): - body = kwargs.get('body', '') + body = kwargs.get('body', None) resp_body = self.get_mock_output([url, body]) if len(resp_body) > 0: ret = json.loads(resp_body) @@ -114,6 +114,29 @@ def _get_mock_output(self, url, kwargs): ret = None return ret + @classmethod + def compare_json_body(cls, obj1, obj2): + if all((not obj1, not obj2)): + # cover the case: obj1={}, obj2=None + return True + else: + return cls.ordered(obj1) == cls.ordered(obj2) + + @classmethod + def ordered(cls, obj): + """Normalize the JSON object. + + from https://stackoverflow.com/questions/25851183/ + how-to-compare-two-json-objects-with-the- + same-elements-in-a-different-order-equa + """ + if isinstance(obj, dict): + return sorted((k, cls.ordered(v)) for k, v in obj.items()) + if isinstance(obj, list): + return sorted(cls.ordered(x) for x in obj) + else: + return obj + @allow_omit_parentheses def patch_rest(output=None, mock_map=None):